mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-10 09:41:16 -03:00
Compare commits
193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7b656017f | ||
|
|
7a8ca73376 | ||
|
|
9eb1826961 | ||
|
|
728a60bd67 | ||
|
|
0099c3c420 | ||
|
|
885d16fcd6 | ||
|
|
c4a8f4c890 | ||
|
|
c098cb5c87 | ||
|
|
63643ff17f | ||
|
|
f83575f084 | ||
|
|
a6c00ca0d2 | ||
|
|
c5eaefc8b5 | ||
|
|
f16bb285be | ||
|
|
09c348bef2 | ||
|
|
561ec7d5f5 | ||
|
|
e98a604a21 | ||
|
|
3341fc888c | ||
|
|
1faf7df371 | ||
|
|
3a128e1484 | ||
|
|
cdc52f7bde | ||
|
|
e0899addcb | ||
|
|
c627509e59 | ||
|
|
4502fc74c3 | ||
|
|
3b0ed061cd | ||
|
|
dfa73c7cc1 | ||
|
|
12be24ef47 | ||
|
|
c684b7c7c7 | ||
|
|
4f22082a5c | ||
|
|
e3c1363831 | ||
|
|
6d413c8dc3 | ||
|
|
32a49e45c8 | ||
|
|
b37d49a708 | ||
|
|
86b7023536 | ||
|
|
287ab597ca | ||
|
|
c313f21066 | ||
|
|
e2dca4273a | ||
|
|
5a7a8003a0 | ||
|
|
b83a7cb659 | ||
|
|
da81328d75 | ||
|
|
5ae4306418 | ||
|
|
ed36f30eae | ||
|
|
7b8ebdadd6 | ||
|
|
bb4e166b37 | ||
|
|
9dc1a7d5e9 | ||
|
|
79f59e2a2d | ||
|
|
8285242ff6 | ||
|
|
c0a54955e7 | ||
|
|
b2d4e85f17 | ||
|
|
a5868d67f5 | ||
|
|
45f1263112 | ||
|
|
4683f4c989 | ||
|
|
ae16397e1c | ||
|
|
2d05b1c1b4 | ||
|
|
ea998b03f2 | ||
|
|
52b2525b0e | ||
|
|
ff96668151 | ||
|
|
d7576a409a | ||
|
|
f6815629fc | ||
|
|
8b3bcd2c4c | ||
|
|
c7bc31fe50 | ||
|
|
bab168f1d1 | ||
|
|
2ab04f4043 | ||
|
|
b32bbb24b9 | ||
|
|
f86f80fcd6 | ||
|
|
d563e428e8 | ||
|
|
5473711a20 | ||
|
|
91009ac9aa | ||
|
|
49bff53370 | ||
|
|
afcab9f1b3 | ||
|
|
841fdf3a04 | ||
|
|
92446bda80 | ||
|
|
a620a1e5ed | ||
|
|
5a8df6cc85 | ||
|
|
b70b966f90 | ||
|
|
97f7c2093b | ||
|
|
8ece4f3ddc | ||
|
|
17a13a8eb7 | ||
|
|
afaf156a42 | ||
|
|
c4f3b5e9ef | ||
|
|
f5916358e5 | ||
|
|
e3e1b34fec | ||
|
|
18bb4ca826 | ||
|
|
007e4662e3 | ||
|
|
e11677ef66 | ||
|
|
194167da32 | ||
|
|
dafeac5c40 | ||
|
|
effea85984 | ||
|
|
0b34836c79 | ||
|
|
f85ce201ee | ||
|
|
80ac4ddc2b | ||
|
|
9a0f712e29 | ||
|
|
286e110fb1 | ||
|
|
988a7fddf3 | ||
|
|
a321505351 | ||
|
|
a074cd62bc | ||
|
|
7a8b468165 | ||
|
|
770fa771b6 | ||
|
|
414fa591b8 | ||
|
|
941b472b37 | ||
|
|
179f575593 | ||
|
|
6400b60bdd | ||
|
|
0e03e872be | ||
|
|
e51322ac81 | ||
|
|
1e739166b3 | ||
|
|
560e53fd5f | ||
|
|
184d58cd36 | ||
|
|
bcf3024cf0 | ||
|
|
9611a3b205 | ||
|
|
8ace1739f5 | ||
|
|
302516a747 | ||
|
|
ad5a6e0552 | ||
|
|
873fd83307 | ||
|
|
d1078f8582 | ||
|
|
0ea668b260 | ||
|
|
91c745e4b5 | ||
|
|
7d73349889 | ||
|
|
53a2c017fe | ||
|
|
80ff583400 | ||
|
|
0c7f74c78d | ||
|
|
13b1ea3f50 | ||
|
|
44ff9956b9 | ||
|
|
add1fa9208 | ||
|
|
8b2059c628 | ||
|
|
15724d0798 | ||
|
|
2839f5e567 | ||
|
|
67c820cee8 | ||
|
|
bce4c78d49 | ||
|
|
421ebcc2d7 | ||
|
|
92df4a6d91 | ||
|
|
22fe8e6a17 | ||
|
|
d0f1870735 | ||
|
|
b71f5d09b0 | ||
|
|
eb00ad77fb | ||
|
|
be886bc6df | ||
|
|
7a5823fd60 | ||
|
|
81d61c467b | ||
|
|
e91e3b6593 | ||
|
|
1db67a5105 | ||
|
|
810faacd72 | ||
|
|
6be3807cae | ||
|
|
4399503f4e | ||
|
|
06b5fdc6e8 | ||
|
|
4037219dc0 | ||
|
|
1612ec50fb | ||
|
|
3bb0163598 | ||
|
|
4d19aa7698 | ||
|
|
f72de8e141 | ||
|
|
02eb856e44 | ||
|
|
c550f4eb21 | ||
|
|
00c25436d7 | ||
|
|
6107d63995 | ||
|
|
eafa0a7169 | ||
|
|
45d2b89780 | ||
|
|
72d73b7fdd | ||
|
|
227a5da02c | ||
|
|
e356bdaa8e | ||
|
|
697d524687 | ||
|
|
73f0d0bb48 | ||
|
|
200ebe43dc | ||
|
|
ff2d354ef8 | ||
|
|
3bef568955 | ||
|
|
9a7be6db08 | ||
|
|
40e2025327 | ||
|
|
a819c863eb | ||
|
|
827c88e4a1 | ||
|
|
e2b7a078f4 | ||
|
|
6de0c4103b | ||
|
|
b6e8171f01 | ||
|
|
b1439075c6 | ||
|
|
7df536023b | ||
|
|
f5f15f9de2 | ||
|
|
0e0a61119f | ||
|
|
6f058c687d | ||
|
|
53ea5d60b7 | ||
|
|
9525f429c6 | ||
|
|
548e379d6a | ||
|
|
202d29de88 | ||
|
|
23152ae8a6 | ||
|
|
7310596dab | ||
|
|
4afe49d7c6 | ||
|
|
d7c3d2acbf | ||
|
|
f771fce892 | ||
|
|
6522000bf0 | ||
|
|
285abcc9bc | ||
|
|
b15e8123ca | ||
|
|
1c86395ed8 | ||
|
|
3c8d2a1126 | ||
|
|
ed8cd08984 | ||
|
|
69537430ea | ||
|
|
0a603a56c6 | ||
|
|
046dd82995 | ||
|
|
97c3e231f4 | ||
|
|
76b782d576 |
543
Makefile.in
543
Makefile.in
@@ -1,10 +1,9 @@
|
||||
#
|
||||
# Copyright (C) 2005 Axel Liljencrantz
|
||||
# Copyright (C) 2005-2006 Axel Liljencrantz
|
||||
#
|
||||
# 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 2
|
||||
# of the License, or (at your option) any later version.
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -32,11 +31,19 @@
|
||||
# hallucinations.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC := @CC@
|
||||
INSTALL:=@INSTALL@
|
||||
|
||||
|
||||
#
|
||||
# Installation directories
|
||||
#
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
datadir = @datadir@
|
||||
@@ -47,54 +54,87 @@ docdir = @docdir@
|
||||
localedir = @localedir@
|
||||
prefix = @prefix@
|
||||
optbindirs = @optbindirs@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
|
||||
|
||||
#
|
||||
# Various flags
|
||||
#
|
||||
|
||||
MACROS=-DLOCALEDIR=\"$(localedir)\" -DPREFIX=L\"$(prefix)\" -DDATADIR=L\"$(datadir)\" -DSYSCONFDIR=L\"$(sysconfdir)\"
|
||||
CFLAGS=@CFLAGS@ $(MACROS)
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS=@CFLAGS@ $(MACROS)
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
LDFLAGS= @LIBS@ @LDFLAGS@
|
||||
|
||||
|
||||
#etc files to install
|
||||
ETC_DIR_INSTALL = etc/fish_interactive.fish
|
||||
|
||||
#
|
||||
# Set to 1 if we have gettext
|
||||
#
|
||||
|
||||
HAVE_GETTEXT=@HAVE_GETTEXT@
|
||||
|
||||
|
||||
#
|
||||
#Additional .c files used by common.o. These also have a corresponding
|
||||
#.h file.
|
||||
#
|
||||
|
||||
COMMON_FILES := util.c halloc.c halloc_util.c fallback.c
|
||||
|
||||
# All objects that the system needs to build fish, except main.o
|
||||
FISH_OBJS := function.o builtin.o complete.o env.o exec.o \
|
||||
expand.o highlight.o history.o kill.o parser.o proc.o reader.o \
|
||||
sanity.o tokenizer.o wildcard.o wgetopt.o wutil.o input.o \
|
||||
output.o intern.o env_universal.o env_universal_common.o \
|
||||
input_common.o event.o signal.o io.o parse_util.o common.o \
|
||||
|
||||
#
|
||||
# All objects that the system needs to build fish, except main.o
|
||||
#
|
||||
|
||||
FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \
|
||||
highlight.o history.o kill.o parser.o proc.o reader.o sanity.o \
|
||||
tokenizer.o wildcard.o wgetopt.o wutil.o input.o output.o intern.o \
|
||||
env_universal.o env_universal_common.o input_common.o event.o \
|
||||
signal.o io.o parse_util.o common.o screen.o path.o
|
||||
|
||||
|
||||
#
|
||||
# Additional files used by builtin.o
|
||||
#
|
||||
|
||||
BUILTIN_FILES := builtin_help.c builtin_set.c builtin_commandline.c \
|
||||
builtin_ulimit.c builtin_complete.c builtin_jobs.c
|
||||
|
||||
# All objects that the system needs to build fish_pager
|
||||
FISH_PAGER_OBJS := fish_pager.o output.o wutil.o \
|
||||
tokenizer.o input_common.o env_universal.o env_universal_common.o \
|
||||
common.o
|
||||
|
||||
#
|
||||
# All objects that the system needs to build fish_pager
|
||||
#
|
||||
|
||||
FISH_PAGER_OBJS := fish_pager.o output.o wutil.o tokenizer.o \
|
||||
input_common.o env_universal.o env_universal_common.o common.o
|
||||
|
||||
|
||||
#
|
||||
# All objects that the system needs to build fish_tests
|
||||
#
|
||||
|
||||
FISH_TESTS_OBJS := $(FISH_OBJS) fish_tests.o
|
||||
|
||||
|
||||
#
|
||||
# All objects that the system needs to build fishd
|
||||
#
|
||||
|
||||
FISHD_OBJS := fishd.o env_universal_common.o wutil.o \
|
||||
doc_src/fishd.o common.o
|
||||
|
||||
|
||||
#
|
||||
# All objects needed to build mimedb
|
||||
#
|
||||
|
||||
MIME_OBJS := mimedb.o xdgmimealias.o xdgmime.o xdgmimeglob.o \
|
||||
xdgmimeint.o xdgmimemagic.o xdgmimeparent.o wutil.o common.o
|
||||
|
||||
|
||||
#
|
||||
# Files containing documentation for builtins.
|
||||
#
|
||||
|
||||
BUILTIN_DOC_SRC := doc_src/source.txt doc_src/and.txt \
|
||||
doc_src/begin.txt doc_src/bg.txt doc_src/bind.txt \
|
||||
doc_src/block.txt doc_src/break.txt doc_src/builtin.txt \
|
||||
@@ -108,41 +148,61 @@ BUILTIN_DOC_SRC := doc_src/source.txt doc_src/and.txt \
|
||||
doc_src/status.txt doc_src/switch.txt doc_src/ulimit.txt \
|
||||
doc_src/while.txt
|
||||
|
||||
|
||||
#
|
||||
# Files generated by running doxygen on the files in $(BUILTIN_DOC_SRC)
|
||||
#
|
||||
|
||||
BUILTIN_DOC_HDR := $(BUILTIN_DOC_SRC:.txt=.doxygen)
|
||||
|
||||
HDR_FILES := doc_src/index.hdr doc_src/commands.hdr doc_src/design.hdr doc_src/license.hdr doc_src/faq.hdr
|
||||
|
||||
#
|
||||
# Files containing documentation for external commands.
|
||||
#
|
||||
|
||||
CMD_DOC_SRC := doc_src/contains.txt doc_src/count.txt doc_src/dirh.txt \
|
||||
doc_src/dirs.txt doc_src/fish_pager.txt doc_src/fishd.txt \
|
||||
doc_src/help.txt doc_src/mimedb.txt doc_src/nextd.txt \
|
||||
doc_src/open.txt doc_src/popd.txt doc_src/prevd.txt \
|
||||
doc_src/psub.txt doc_src/pushd.txt doc_src/set_color.txt \
|
||||
doc_src/trap.txt doc_src/type.txt doc_src/umask.txt \
|
||||
doc_src/vared.txt
|
||||
doc_src/dirs.txt doc_src/fish.txt doc_src/fish_pager.txt \
|
||||
doc_src/fishd.txt doc_src/help.txt doc_src/isatty.txt \
|
||||
doc_src/mimedb.txt doc_src/nextd.txt doc_src/open.txt \
|
||||
doc_src/popd.txt doc_src/prevd.txt doc_src/psub.txt \
|
||||
doc_src/pushd.txt doc_src/set_color.txt doc_src/trap.txt \
|
||||
doc_src/type.txt doc_src/umask.txt doc_src/vared.txt
|
||||
|
||||
|
||||
#
|
||||
# Files generated by running doxygen on the files in $(CMD_DOC_SRC)
|
||||
#
|
||||
|
||||
CMD_DOC_HDR := $(CMD_DOC_SRC:.txt=.doxygen)
|
||||
|
||||
|
||||
#
|
||||
# Files in the test directory
|
||||
#
|
||||
|
||||
TEST_IN := $(wildcard tests/test*.in)
|
||||
|
||||
|
||||
#
|
||||
# Files that should be added to the tar archives
|
||||
#
|
||||
|
||||
#
|
||||
# Files in ./doc_src/
|
||||
DOC_SRC_DIR_FILES := doc_src/Doxyfile.in doc_src/doc.hdr \
|
||||
$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/fish.1.in
|
||||
#
|
||||
|
||||
DOC_SRC_DIR_FILES := doc_src/Doxyfile.in doc_src/index.hdr \
|
||||
doc_src/license.hdr doc_src/faq.hdr doc_src/design.hdr \
|
||||
$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)
|
||||
|
||||
|
||||
#
|
||||
# Files in ./. There is some overlap between the variables in the
|
||||
# list, so when copying these files, cp will complain that some files
|
||||
# are specified more than once.
|
||||
#
|
||||
|
||||
# Files in ./
|
||||
MAIN_DIR_FILES := Doxyfile Doxyfile.user Makefile.in configure \
|
||||
configure.ac config.h.in install-sh set_color.c count.c \
|
||||
key_reader.c gen_hdr.sh gen_hdr2.c $(MIME_OBJS:.o=.h) \
|
||||
@@ -152,68 +212,124 @@ MAIN_DIR_FILES := Doxyfile Doxyfile.user Makefile.in configure \
|
||||
xsel-0.9.6.tar ChangeLog config.sub config.guess fish_tests.c \
|
||||
main.c fish_pager.c fishd.c seq.in
|
||||
|
||||
|
||||
#
|
||||
# Files in ./etc/
|
||||
ETC_DIR_FILES :=etc/fish.in etc/fish_inputrc \
|
||||
etc/fish_interactive.fish.in
|
||||
#
|
||||
|
||||
ETC_DIR_FILES :=etc/config.fish.in etc/fish_inputrc
|
||||
|
||||
|
||||
#
|
||||
# Files in ./share/
|
||||
SHARE_DIR_FILES :=share/fish.in
|
||||
#
|
||||
|
||||
SHARE_DIR_FILES :=share/config.fish.in share/config_interactive.fish.in
|
||||
|
||||
|
||||
#
|
||||
# Files in ./tests/
|
||||
#
|
||||
|
||||
TESTS_DIR_FILES := $(TEST_IN) $(TEST_IN:.in=.out) $(TEST_IN:.in=.err) \
|
||||
$(TEST_IN:.in=.status) tests/test.fish tests/gen_output.fish
|
||||
|
||||
|
||||
#
|
||||
# Files in ./share/completions/
|
||||
#
|
||||
|
||||
COMPLETIONS_DIR_FILES := $(wildcard share/completions/*.fish)
|
||||
|
||||
|
||||
#
|
||||
# Files in ./share/functions/
|
||||
#
|
||||
|
||||
FUNCTIONS_DIR_FILES := $(wildcard share/functions/*.fish)
|
||||
|
||||
# Programs to build
|
||||
|
||||
#
|
||||
# Programs to install
|
||||
#
|
||||
|
||||
PROGRAMS:=fish set_color @XSEL@ @SEQ_FALLBACK@ mimedb count fish_pager fishd
|
||||
|
||||
# Manuals to install
|
||||
MANUALS:=doc_src/fish.1 @XSEL_MAN_PATH@ \
|
||||
doc_src/builtin_doc/man/man1/mimedb.1 \
|
||||
doc_src/builtin_doc/man/man1/set_color.1 \
|
||||
doc_src/builtin_doc/man/man1/count.1 \
|
||||
doc_src/builtin_doc/man/man1/fishd.1 \
|
||||
|
||||
#
|
||||
# Manual pagess to install
|
||||
#
|
||||
|
||||
MANUALS:=doc_src/builtin_doc/man/man1/fish.1 @XSEL_MAN_PATH@ \
|
||||
doc_src/builtin_doc/man/man1/mimedb.1 \
|
||||
doc_src/builtin_doc/man/man1/set_color.1 \
|
||||
doc_src/builtin_doc/man/man1/count.1 \
|
||||
doc_src/builtin_doc/man/man1/fishd.1 \
|
||||
doc_src/builtin_doc/man/man1/fish_pager.1
|
||||
|
||||
#All translation message catalogs
|
||||
|
||||
#
|
||||
# All translation message catalogs
|
||||
#
|
||||
|
||||
TRANSLATIONS_SRC := $(wildcard po/*.po)
|
||||
TRANSLATIONS := $(TRANSLATIONS_SRC:.po=.gmo)
|
||||
|
||||
#Make everything needed for installing fish
|
||||
all: $(PROGRAMS) user_doc etc/fish share/fish etc/fish_interactive.fish $(TRANSLATIONS)
|
||||
|
||||
#
|
||||
# Make everything needed for installing fish
|
||||
#
|
||||
|
||||
all: $(PROGRAMS) user_doc etc/config.fish share/config.fish share/config_interactive.fish $(TRANSLATIONS)
|
||||
@echo fish has now been built.
|
||||
@echo Use \'make install\' to install fish.
|
||||
.PHONY: all
|
||||
|
||||
|
||||
#
|
||||
# These dependencies make sure that autoconf and configure are run
|
||||
# when the source code for the build configuration has changed.
|
||||
#
|
||||
|
||||
configure: configure.ac
|
||||
./config.status --recheck
|
||||
|
||||
Makefile: Makefile.in configure
|
||||
./config.status
|
||||
|
||||
fish.spec: fish.spec.in
|
||||
./config.status
|
||||
|
||||
#
|
||||
# Build fish with some debug flags specified. This is GCC specific,
|
||||
# and should only be used when debuging fish.
|
||||
#
|
||||
|
||||
debug:
|
||||
make fish CFLAGS="@CFLAGS@ $(MACROS) -O0 -Wno-unused -Werror -g"
|
||||
.PHONY: debug
|
||||
|
||||
|
||||
#
|
||||
# User documentation, describing the features of the fish shell.
|
||||
user_doc: doc_src/doc.hdr Doxyfile.user user_doc.head.html
|
||||
$(MAKE) doc.h # Depend on the source (doc.hdr) and manually make the intermediate as needed
|
||||
#
|
||||
|
||||
user_doc: $(HDR_FILES) Doxyfile.user user_doc.head.html $(CMD_DOC_SRC) $(BUILTIN_DOC_SRC)
|
||||
$(MAKE) doc.h # Depend on the sources (*.hdr) and manually make the intermediate as needed
|
||||
doxygen Doxyfile.user
|
||||
touch user_doc
|
||||
|
||||
|
||||
#
|
||||
# Source code documentation. Also includes user documentation.
|
||||
#
|
||||
|
||||
doc: *.h *.c doc.h Doxyfile builtin_help.c
|
||||
doxygen;
|
||||
|
||||
|
||||
#
|
||||
# PDF version of the source code documentation.
|
||||
#
|
||||
|
||||
doc/refman.pdf: doc
|
||||
cd doc/latex;
|
||||
make;
|
||||
@@ -221,56 +337,100 @@ doc/refman.pdf: doc
|
||||
cd ../..;
|
||||
rm -r doc/latex;
|
||||
|
||||
|
||||
#
|
||||
# This target runs both the low level code tests and the high level script tests.
|
||||
#
|
||||
|
||||
test: $(PROGRAMS) fish_tests
|
||||
./fish_tests; cd tests; ../fish <test.fish;
|
||||
.PHONY: test
|
||||
|
||||
|
||||
#
|
||||
# Build the xsel program, which is maintained in its own tarball
|
||||
#
|
||||
|
||||
xsel-0.9.6:
|
||||
tar -xf xsel-0.9.6.tar
|
||||
|
||||
xsel-0.9.6/xsel: xsel-0.9.6
|
||||
cd xsel-0.9.6; ./configure; make
|
||||
|
||||
|
||||
#
|
||||
# commands.hdr collects documentation on all commands, functions and
|
||||
# builtins
|
||||
#
|
||||
|
||||
doc_src/commands.hdr:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)
|
||||
rm -f commands.tmp;
|
||||
echo "/** \page commands Commands" >>commands.tmp;
|
||||
echo "Fish ships with a large number of builtin commands, shellscript functions and external commandss. These are all described below. " >>commands.tmp;
|
||||
for i in `printf "%s\n" $(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)|sort`; do \
|
||||
echo "<hr>" >>commands.tmp; \
|
||||
cat $$i >>commands.tmp; \
|
||||
echo >>commands.tmp; \
|
||||
echo >>commands.tmp; \
|
||||
echo "Back to <a href='index.html#toc-commands'>index</a>". >>commands.tmp; \
|
||||
done
|
||||
echo "*/" >>commands.tmp
|
||||
mv commands.tmp doc_src/commands.hdr
|
||||
|
||||
|
||||
#
|
||||
# doc.h is a compilation of the various snipptes of text used both for
|
||||
# the user documentation and for internal help functions into a single
|
||||
# file that can be parsed dy Doxygen to generate the user
|
||||
# documentation.
|
||||
doc.h:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/doc.hdr
|
||||
cat doc_src/doc.hdr >doc.h;
|
||||
echo "/** \page builtins Builtin commands" >>doc.h;
|
||||
for i in `printf "%s\n" $(BUILTIN_DOC_SRC)|sort`; do \
|
||||
echo "<hr>" >>doc.h; \
|
||||
cat $$i >>doc.h; \
|
||||
done
|
||||
echo "*/" >>doc.h
|
||||
echo "/** \page commands External commands" >>doc.h;
|
||||
echo "\c fish is shipped with commands which do not use any internal parts of the shell, and are therefore not written as builtins, but separate commands." >>doc.h
|
||||
for i in `printf "%s\n" $(CMD_DOC_SRC)|sort`; do \
|
||||
echo "<hr>" >>doc.h; \
|
||||
cat $$i >>doc.h; \
|
||||
done
|
||||
echo "*/" >>doc.h
|
||||
#
|
||||
|
||||
doc.h:$(HDR_FILES)
|
||||
rm -f doc.h
|
||||
echo "/** \mainpage Fish user documentation" >doc.tmp
|
||||
echo "\section toc Table of contents" >>doc.tmp
|
||||
echo '- <a href="index.html" name="toc-index">Fish user documentation</a>' >>doc.tmp
|
||||
for i in $(HDR_FILES); do\
|
||||
sed <$$i >>doc.tmp -n \
|
||||
-e 's,.*\\page *\([^ ]*\) *\(.*\)$$,- <a href="'`basename $$i .hdr`'.html" name="toc-'`basename $$i .hdr`'">\2</a>,p' \
|
||||
-e 's,.*\\section *\([^ ]*\) *\(.*\)$$, - <a href="'`basename $$i .hdr`'.html#\1" name="toc-'`basename $$i .hdr`'">\2</a>,p' \
|
||||
# -e 's,.*\\subsection *\([^ ]*\) *\(.*\)$$, - <a href="'`basename $$i .hdr`'.html#\1" name="toc-'`basename $$i .hdr`'">\2</a>,p'; \
|
||||
done
|
||||
cat $(HDR_FILES) >>doc.tmp;
|
||||
mv doc.tmp doc.h
|
||||
|
||||
|
||||
#
|
||||
# This rule creates complete doxygen headers from each of the various
|
||||
# snipptes of text used both for the user documentation and for
|
||||
# internal help functions, that can be parsed to Doxygen to generate
|
||||
# the internal help function text.
|
||||
#
|
||||
|
||||
%.doxygen:%.txt
|
||||
echo "/** \page " `basename $*` >$@;
|
||||
cat $*.txt >>$@;
|
||||
echo "*/" >>$@
|
||||
|
||||
%: %.in Makefile
|
||||
sed <$@.in >$@ -e "s,@sysconfdir\@,$(sysconfdir)," -e "s,@datadir\@,$(datadir)," -e "s,@docdir\@,$(docdir)," -e "s|@configure_input\@|$@, generated from $@.in by the Makefile. DO NOT MANUALLY EDIT THIS FILE!|" -e "s,@prefix\@,$(prefix)," -e "s,@optbindirs\@,$(optbindirs),"
|
||||
sed <$@.in >$@ -e "s,@sysconfdir\@,$(sysconfdir),g" -e "s,@datadir\@,$(datadir),g" -e "s,@docdir\@,$(docdir),g" -e "s|@configure_input\@|$@, generated from $@.in by the Makefile. DO NOT MANUALLY EDIT THIS FILE!|g" -e "s,@prefix\@,$(prefix),g" -e "s,@optbindirs\@,$(optbindirs),g"
|
||||
#-e "s,@\@,$(),"
|
||||
|
||||
# Compile translation file
|
||||
|
||||
#
|
||||
# Compile translation files to binary format
|
||||
#
|
||||
|
||||
%.gmo:
|
||||
if test $(HAVE_GETTEXT) = 1; then \
|
||||
msgfmt -o $*.gmo $*.po; \
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Update existing po file or copy messages.pot
|
||||
#
|
||||
|
||||
%.po:messages.pot
|
||||
if test $(HAVE_GETTEXT) = 1;then \
|
||||
if test -f $*.po; then \
|
||||
@@ -280,7 +440,11 @@ doc.h:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/doc.hdr
|
||||
fi; \
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Create a template translation object
|
||||
#
|
||||
|
||||
messages.pot: *.c *.h etc/*.in share/fish share/completions/*.fish share/functions/*.fish seq
|
||||
if test $(HAVE_GETTEXT) = 1;then \
|
||||
xgettext -k_ -kN_ *.c *.h -o messages.pot; \
|
||||
@@ -295,6 +459,8 @@ builtin.o: $(BUILTIN_FILES)
|
||||
|
||||
common.o: $(COMMON_FILES)
|
||||
|
||||
|
||||
#
|
||||
# Generate the internal help functions by making doxygen create
|
||||
# man-pages which are then converted into C code. The convertion path
|
||||
# looks like this:
|
||||
@@ -326,6 +492,7 @@ common.o: $(COMMON_FILES)
|
||||
#
|
||||
# Which is an awful, clunky and ugly way of producing
|
||||
# documentation. There ought to be something simpler.
|
||||
#
|
||||
|
||||
doc_src/builtin_doc: $(BUILTIN_DOC_SRC) doc_src/count.txt builtin_help.hdr $(CMD_DOC_SRC)
|
||||
for i in $(BUILTIN_DOC_SRC) $(CMD_DOC_SRC); do \
|
||||
@@ -336,7 +503,9 @@ doc_src/builtin_doc: $(BUILTIN_DOC_SRC) doc_src/count.txt builtin_help.hdr $(CMD
|
||||
done
|
||||
cd doc_src; doxygen; cd ..;
|
||||
for i in doc_src/builtin_doc/man/man1/*.1; do \
|
||||
sed -i -e "s/\(.\)\\.SH/\1/" $$i; \
|
||||
CMD_NAME=`basename $$i .1`; \
|
||||
sed -e "s/\(.\)\\.SH/\1/" -e "s/$$CMD_NAME *\\\\- *\"\(.*\)\"/\1/" <$$i >$$i.tmp; \
|
||||
mv $$i.tmp $$i; \
|
||||
done
|
||||
touch doc_src/builtin_doc
|
||||
|
||||
@@ -351,11 +520,12 @@ builtin_help.c: doc_src/builtin_doc gen_hdr.sh
|
||||
done;
|
||||
echo "}" >>builtin_help.c
|
||||
|
||||
|
||||
#
|
||||
# Generate help texts for external fish commands, like set_color and
|
||||
# mimedb. Depends on builtin_help.c to make sure doxygen gets run to
|
||||
# generate the man files.
|
||||
# mimedb.
|
||||
#
|
||||
|
||||
%.c : %.doxygen
|
||||
$(MAKE) gen_hdr2 builtin_help.c # These should really be filed as dependencis for %.c above instead, but that seems to confuse make
|
||||
echo "// This file was automatically generated, do not edit" >$@
|
||||
@@ -374,8 +544,10 @@ builtin_help.c: doc_src/builtin_doc gen_hdr.sh
|
||||
# The build rules for installing/uninstalling fish
|
||||
#
|
||||
|
||||
#
|
||||
# Check for an incompatible installed fish version, and fail with an
|
||||
# error if found
|
||||
#
|
||||
|
||||
check-uninstall:
|
||||
if test -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish -o -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish; then \
|
||||
@@ -383,46 +555,70 @@ check-uninstall:
|
||||
echo ERROR;\
|
||||
echo;\
|
||||
echo An older fish installation using an incompatible filesystem hierarchy was detected;\
|
||||
echo You must uninstall this fish version before installing proceeding;\
|
||||
echo You must uninstall this fish version before proceeding;\
|
||||
echo type \'make uninstall-legacy\' to uninstall these files,;\
|
||||
echo or type \'make force-install\' to force installation.;\
|
||||
echo The latter may result in a broken installation.;\
|
||||
echo;\
|
||||
false;\
|
||||
fi;
|
||||
if test -f $(DESTDIR)$(sysconfdir)/fish; then \
|
||||
echo;\
|
||||
echo ERROR;\
|
||||
echo;\
|
||||
echo An older fish installation using an incompatible filesystem hierarchy was detected;\
|
||||
echo You must remove the file $(DESTDIR)$(sysconfdir)/fish before proceeding;\
|
||||
echo type \'make uninstall-legacy\' to uninstall this file,;\
|
||||
echo or remove it manually using \'rm $(DESTDIR)$(sysconfdir)/fish\'.;\
|
||||
echo;\
|
||||
false;\
|
||||
fi;
|
||||
.PHONY: check-uninstall
|
||||
|
||||
|
||||
#
|
||||
# This check makes sure that the install-sh script is executable. The
|
||||
# darcs repo doesn't preserve the executable bit, so this needs to be
|
||||
# run after checkout.
|
||||
#
|
||||
|
||||
install-sh:
|
||||
if test -x install-sh; then true; else chmod 755 install-sh; fi
|
||||
.PHONY: install-sh
|
||||
|
||||
# Try to install after checking for incompatible installed versions
|
||||
|
||||
#
|
||||
# Try to install after checking for incompatible installed versions.
|
||||
#
|
||||
|
||||
install: all install-sh check-uninstall install-force
|
||||
.PHONY: install
|
||||
|
||||
|
||||
#
|
||||
# Force installation, even in presense of incompatible previous
|
||||
# version
|
||||
# version. This may fail.
|
||||
#
|
||||
|
||||
install-force: all install-translations
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
|
||||
for i in $(PROGRAMS); do\
|
||||
$(INSTALL) -m 755 $$i $(DESTDIR)$(bindir) ; \
|
||||
done;
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)/fish.d
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)/fish
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/completions
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/functions
|
||||
$(INSTALL) -m 644 etc/fish $(DESTDIR)$(sysconfdir)/fish
|
||||
$(INSTALL) -m 644 share/fish $(DESTDIR)$(datadir)/fish
|
||||
for i in $(ETC_DIR_INSTALL); do \
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(sysconfdir)/fish.d; \
|
||||
done;
|
||||
$(INSTALL) -m 644 etc/config.fish $(DESTDIR)$(sysconfdir)/fish/
|
||||
$(INSTALL) -m 644 share/config.fish $(DESTDIR)$(datadir)/fish/
|
||||
$(INSTALL) -m 644 share/config_interactive.fish $(DESTDIR)$(datadir)/fish/
|
||||
for i in $(COMPLETIONS_DIR_FILES); do \
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/completions/; \
|
||||
done;
|
||||
for i in $(FUNCTIONS_DIR_FILES); do \
|
||||
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/functions/; \
|
||||
done;
|
||||
$(INSTALL) -m 644 etc/fish_inputrc $(DESTDIR)$(sysconfdir)/fish_inputrc;
|
||||
$(INSTALL) -m 644 etc/fish_inputrc $(DESTDIR)$(sysconfdir)/fish/fish_inputrc;
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(docdir)
|
||||
for i in user_doc/html/* ChangeLog; do \
|
||||
if test -f $$i; then \
|
||||
@@ -444,38 +640,42 @@ install-force: all install-translations
|
||||
.PHONY: install-force
|
||||
|
||||
|
||||
#
|
||||
# Uninstall this fish version
|
||||
#
|
||||
|
||||
uninstall: uninstall-translations
|
||||
for i in $(PROGRAMS); do \
|
||||
-for i in $(PROGRAMS); do \
|
||||
rm -f $(DESTDIR)$(bindir)/$$i; \
|
||||
done;
|
||||
rm -f $(DESTDIR)$(bindir)/xsel
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish_inputrc
|
||||
if test -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish; then \
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish; \
|
||||
fi
|
||||
if test -d $(DESTDIR)$(datadir)/fish; then \
|
||||
-rm -f $(DESTDIR)$(bindir)/xsel
|
||||
-rm -f $(DESTDIR)$(sysconfdir)/fish/config.fish
|
||||
-rm -f $(DESTDIR)$(sysconfdir)/fish/fish_inputrc
|
||||
-rmdir $(DESTDIR)$(sysconfdir)/fish
|
||||
-if test -d $(DESTDIR)$(datadir)/fish; then \
|
||||
rm -r $(DESTDIR)$(datadir)/fish; \
|
||||
fi
|
||||
if test -d $(DESTDIR)$(docdir); then \
|
||||
-if test -d $(DESTDIR)$(docdir); then \
|
||||
rm -r $(DESTDIR)$(docdir);\
|
||||
fi
|
||||
for i in $(MANUALS); do \
|
||||
-for i in $(MANUALS); do \
|
||||
rm -f $(DESTDIR)$(mandir)/man1/`basename $$i`*; \
|
||||
done;
|
||||
.PHONY: uninstall
|
||||
|
||||
# Uninstall older fish release. This is not the default uninstall
|
||||
|
||||
#
|
||||
# Uninstall an older fish release. This is not the default uninstall
|
||||
# since there is a slight chance that it removes a file put in place by
|
||||
# the sysadmin.
|
||||
# the sysadmin. But if 'make install' detects a file confligt, it
|
||||
# suggests using this target.
|
||||
#
|
||||
|
||||
uninstall-legacy: uninstall
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish
|
||||
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish
|
||||
if test -d $(DESTDIR)$(sysconfdir)/fish.d/completions; then \
|
||||
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish
|
||||
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish
|
||||
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish
|
||||
-if test -d $(DESTDIR)$(sysconfdir)/fish.d/completions; then \
|
||||
for i in $(COMPLETIONS_DIR_FILES); do \
|
||||
basename=`basename $$i`; \
|
||||
if test -f $(DESTDIR)$(sysconfdir)/fish.d/completions/$$basename; then \
|
||||
@@ -483,8 +683,9 @@ uninstall-legacy: uninstall
|
||||
fi; \
|
||||
done; \
|
||||
fi;
|
||||
rmdir $(DESTDIR)$(sysconfdir)/fish.d/completions; true
|
||||
rmdir $(DESTDIR)$(sysconfdir)/fish.d; true
|
||||
-rmdir $(DESTDIR)$(sysconfdir)/fish.d/completions
|
||||
-rmdir $(DESTDIR)$(sysconfdir)/fish.d
|
||||
-rm $(DESTDIR)$(sysconfdir)/fish
|
||||
@echo The previous fish installation has been removed.
|
||||
.PHONY: uninstall-legacy
|
||||
|
||||
@@ -506,41 +707,87 @@ uninstall-translations:
|
||||
fi
|
||||
.PHONY: uninstall-translations
|
||||
|
||||
|
||||
#
|
||||
# The build rules for all the commands
|
||||
#
|
||||
|
||||
#
|
||||
# Build the fish program.
|
||||
#
|
||||
|
||||
fish: $(FISH_OBJS) main.o
|
||||
$(CC) $(FISH_OBJS) main.o $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Build the fish_pager program.
|
||||
#
|
||||
|
||||
fish_pager: $(FISH_PAGER_OBJS)
|
||||
$(CC) $(FISH_PAGER_OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Build the fishd program.
|
||||
#
|
||||
|
||||
fishd: $(FISHD_OBJS)
|
||||
$(CC) $(FISHD_OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Build the fish_tests program.
|
||||
#
|
||||
|
||||
fish_tests: $(FISH_TESTS_OBJS)
|
||||
$(CC) $(FISH_TESTS_OBJS) $(LDFLAGS) -o $@
|
||||
|
||||
# mimedb does not need any libraries, so we don't use LDFLAGS here
|
||||
|
||||
#
|
||||
# Build the mimedb program.
|
||||
#
|
||||
# mimedb does not need any libraries, so we don't use LDFLAGS here.
|
||||
#
|
||||
|
||||
mimedb: $(MIME_OBJS) doc_src/mimedb.o
|
||||
$(CC) $(MIME_OBJS) doc_src/mimedb.o $(LDFLAGS) -o $@
|
||||
|
||||
# count does not need any libraries, so we don't use LDFLAGS here
|
||||
|
||||
#
|
||||
# Build the count program.
|
||||
#
|
||||
# count does not need any libraries, so we don't use LDFLAGS here.
|
||||
#
|
||||
|
||||
count: count.o
|
||||
$(CC) count.o -o $@
|
||||
|
||||
set_color: set_color.o doc_src/set_color.o common.o
|
||||
$(CC) set_color.o doc_src/set_color.o common.o $(LDFLAGS) -o $@
|
||||
|
||||
#
|
||||
# Build the set_color program
|
||||
#
|
||||
|
||||
set_color: set_color.o doc_src/set_color.o common.o
|
||||
$(CC) set_color.o doc_src/set_color.o common.o wutil.o $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Test program for the tokenizer library
|
||||
#
|
||||
|
||||
tokenizer_test: tokenizer.c tokenizer.h wutil.o common.o
|
||||
$(CC) $(CFLAGS) tokenizer.c wutil.o common.o -D TOKENIZER_TEST $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Neat little program to show output from terminal
|
||||
#
|
||||
|
||||
key_reader: key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o
|
||||
$(CC) key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o $(LDFLAGS) -o $@
|
||||
|
||||
|
||||
#
|
||||
# Update dependencies
|
||||
#
|
||||
@@ -549,12 +796,16 @@ depend:
|
||||
./config.status
|
||||
.PHONY: depend
|
||||
|
||||
|
||||
#
|
||||
# Copy all the source files into a new directory and use tar to create
|
||||
# an archive from it. Simplest way I could think of to make an archive
|
||||
# witout backups, autogenerated files, etc.
|
||||
#
|
||||
# Uses install instead of mkdir so build won't fail if the directory
|
||||
# exists
|
||||
#
|
||||
|
||||
fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(ETC_DIR_FILES) $(TEST_DIR_FILES) $(SHARE_DIR_FILES) $(FUNCTIONS_DIR_FILES) $(COMPLETIONS_DIR_FILES) ChangeLog user_doc doc_src/builtin_doc
|
||||
rm -rf fish-@PACKAGE_VERSION@
|
||||
$(INSTALL) -d fish-@PACKAGE_VERSION@
|
||||
@@ -579,9 +830,19 @@ fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(ETC_DIR_FIL
|
||||
tar -c fish-@PACKAGE_VERSION@ >fish-@PACKAGE_VERSION@.tar
|
||||
rm -rf fish-@PACKAGE_VERSION@
|
||||
|
||||
|
||||
#
|
||||
# Just an alias for fish-@PACKAGE_VERSION@.tar
|
||||
#
|
||||
|
||||
tar: fish-@PACKAGE_VERSION@.tar
|
||||
.PHONY: tar
|
||||
|
||||
|
||||
#
|
||||
# Make compressed tar archives
|
||||
#
|
||||
|
||||
fish-@PACKAGE_VERSION@.tar.gz: fish-@PACKAGE_VERSION@.tar
|
||||
gzip -f --best -c fish-@PACKAGE_VERSION@.tar >fish-@PACKAGE_VERSION@.tar.gz
|
||||
|
||||
@@ -591,8 +852,19 @@ fish-@PACKAGE_VERSION@.tar.bz2: fish-@PACKAGE_VERSION@.tar
|
||||
dist: fish-@PACKAGE_VERSION@.tar.bz2
|
||||
.PHONY: dist
|
||||
|
||||
#
|
||||
# Build the RPM spec file.
|
||||
#
|
||||
|
||||
fish.spec: fish.spec.in
|
||||
./config.status
|
||||
|
||||
|
||||
#
|
||||
# Create .rpm file for the current systems architecture and an
|
||||
# .src.rpm file.
|
||||
#
|
||||
|
||||
rpm: fish-@PACKAGE_VERSION@.tar.bz2 fish.spec
|
||||
@if which rpmbuild; then true; else \
|
||||
echo Could not find the rpmbuild command, needed to build an rpm; \
|
||||
@@ -607,18 +879,29 @@ rpm: fish-@PACKAGE_VERSION@.tar.bz2 fish.spec
|
||||
mv /usr/src/redhat/SRPMS/fish*@PACKAGE_VERSION@*.src.rpm .
|
||||
.PHONY: rpm
|
||||
|
||||
|
||||
#
|
||||
# Cleanup targets
|
||||
#
|
||||
|
||||
#
|
||||
# distclean should restore the tree to the state right after extracting a tarball.
|
||||
#
|
||||
|
||||
distclean: clean
|
||||
rm -f fish.spec doc_src/fish.1 doc_src/Doxyfile
|
||||
rm -f etc/fish etc/fish_interactive.fish seq
|
||||
rm -f fish.spec doc_src/Doxyfile
|
||||
rm -f etc/config.fish share/config_interactive.fish seq share/config.fish
|
||||
rm -f config.status config.log config.h Makefile
|
||||
.PHONY: distclean
|
||||
|
||||
|
||||
#
|
||||
# clean removes everything built by the makefile, but not things that
|
||||
# are created by the configure script.
|
||||
#
|
||||
|
||||
clean:
|
||||
rm -f *.o doc.h doc_src/*.doxygen doc_src/*.c builtin_help.c doc_src/*.o
|
||||
rm -f *.o doc.h doc.tmp doc_src/*.doxygen doc_src/*.c doc_src/*.o doc_src/commands.hdr
|
||||
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
|
||||
rm -f tokenizer_test fish key_reader set_color gen_hdr2 mimedb
|
||||
rm -f fishd fish_pager count fish_tests
|
||||
@@ -626,41 +909,41 @@ clean:
|
||||
rm -f fish-@PACKAGE_VERSION@.tar.gz
|
||||
rm -f fish-@PACKAGE_VERSION@.tar.bz2
|
||||
rm -rf doc;
|
||||
rm -rf user_doc;
|
||||
rm -rf doc_src/builtin_doc
|
||||
rm -rf fish-@PACKAGE_VERSION@
|
||||
rm -rf xsel-0.9.6/
|
||||
rm -f $(TRANSLATIONS)
|
||||
.PHONY: clean
|
||||
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
builtin.o: config.h fallback.h util.h wutil.h builtin.h function.h complete.h
|
||||
builtin.o: proc.h io.h parser.h event.h reader.h env.h common.h wgetopt.h
|
||||
builtin.o: sanity.h tokenizer.h wildcard.h input_common.h input.h intern.h
|
||||
builtin.o: signal.h halloc.h halloc_util.h parse_util.h expand.h
|
||||
builtin.o: signal.h halloc.h halloc_util.h parse_util.h expand.h path.h
|
||||
builtin.o: builtin_help.c builtin_set.c builtin_commandline.c
|
||||
builtin.o: builtin_complete.c builtin_ulimit.c builtin_jobs.c
|
||||
builtin_commandline.o: signal.h config.h fallback.h util.h wutil.h builtin.h
|
||||
builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h builtin.h
|
||||
builtin_commandline.o: common.h wgetopt.h reader.h proc.h io.h parser.h
|
||||
builtin_commandline.o: event.h tokenizer.h input_common.h input.h
|
||||
builtin_commandline.o: parse_util.h
|
||||
builtin_complete.o: signal.h config.h fallback.h util.h wutil.h builtin.h
|
||||
builtin_complete.o: config.h signal.h fallback.h util.h wutil.h builtin.h
|
||||
builtin_complete.o: common.h complete.h wgetopt.h parser.h proc.h io.h
|
||||
builtin_complete.o: event.h reader.h
|
||||
builtin_help.o: config.h util.h common.h halloc_util.h
|
||||
builtin_jobs.o: config.h fallback.h util.h wutil.h builtin.h proc.h io.h
|
||||
builtin_jobs.o: parser.h event.h common.h wgetopt.h
|
||||
builtin_set.o: signal.h config.h fallback.h util.h wutil.h builtin.h env.h
|
||||
builtin_set.o: config.h signal.h fallback.h util.h wutil.h builtin.h env.h
|
||||
builtin_set.o: expand.h common.h wgetopt.h proc.h io.h parser.h event.h
|
||||
builtin_ulimit.o: config.h fallback.h util.h builtin.h common.h wgetopt.h
|
||||
common.o: config.h fallback.h util.h wutil.h common.h expand.h proc.h io.h
|
||||
common.o: wildcard.h parser.h event.h util.c halloc.c halloc.h halloc_util.c
|
||||
common.o: fallback.c
|
||||
complete.o: signal.h config.h fallback.h util.h tokenizer.h wildcard.h proc.h
|
||||
complete.o: config.h signal.h fallback.h util.h tokenizer.h wildcard.h proc.h
|
||||
complete.o: io.h parser.h event.h function.h complete.h builtin.h env.h
|
||||
complete.o: exec.h expand.h common.h reader.h history.h intern.h parse_util.h
|
||||
complete.o: halloc.h halloc_util.h wutil.h
|
||||
complete.o: halloc.h halloc_util.h wutil.h path.h
|
||||
count.o: config.h
|
||||
env.o: config.h signal.h fallback.h util.h wutil.h proc.h io.h common.h env.h
|
||||
env.o: sanity.h expand.h history.h reader.h parser.h event.h env_universal.h
|
||||
env.o: env_universal_common.h input_common.h complete.h
|
||||
@@ -668,35 +951,37 @@ env_universal.o: config.h signal.h fallback.h util.h common.h wutil.h
|
||||
env_universal.o: env_universal_common.h env_universal.h
|
||||
env_universal_common.o: config.h signal.h fallback.h util.h common.h wutil.h
|
||||
env_universal_common.o: env_universal_common.h
|
||||
event.o: signal.h config.h fallback.h util.h wutil.h function.h proc.h io.h
|
||||
event.o: config.h signal.h fallback.h util.h wutil.h function.h proc.h io.h
|
||||
event.o: parser.h event.h common.h halloc_util.h
|
||||
exec.o: signal.h config.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
exec.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
exec.o: exec.h parser.h event.h builtin.h function.h env.h wildcard.h
|
||||
exec.o: sanity.h expand.h env_universal.h env_universal_common.h halloc.h
|
||||
exec.o: halloc_util.h parse_util.h
|
||||
expand.o: signal.h config.h fallback.h util.h common.h wutil.h env.h proc.h
|
||||
expand.o: config.h signal.h fallback.h util.h common.h wutil.h env.h proc.h
|
||||
expand.o: io.h parser.h event.h expand.h wildcard.h exec.h tokenizer.h
|
||||
expand.o: complete.h parse_util.h halloc_util.h
|
||||
expand.o: complete.h parse_util.h halloc.h halloc_util.h
|
||||
fallback.o: config.h fallback.h util.h
|
||||
fishd.o: config.h signal.h fallback.h util.h common.h wutil.h
|
||||
fishd.o: env_universal_common.h
|
||||
fishd.o: env_universal_common.h halloc.h halloc_util.h path.h
|
||||
fish_pager.o: config.h signal.h fallback.h util.h wutil.h common.h complete.h
|
||||
fish_pager.o: output.h input_common.h env_universal.h env_universal_common.h
|
||||
fish_pager.o: halloc.h halloc_util.h
|
||||
fish_tests.o: config.h signal.h fallback.h util.h common.h proc.h io.h
|
||||
fish_tests.o: reader.h builtin.h function.h complete.h wutil.h env.h expand.h
|
||||
fish_tests.o: parser.h event.h tokenizer.h output.h exec.h halloc_util.h
|
||||
function.o: signal.h config.h wutil.h fallback.h util.h function.h proc.h
|
||||
function.o: config.h signal.h wutil.h fallback.h util.h function.h proc.h
|
||||
function.o: io.h parser.h event.h common.h intern.h reader.h parse_util.h
|
||||
function.o: env.h expand.h
|
||||
halloc.o: config.h fallback.h util.h common.h halloc.h
|
||||
halloc_util.o: config.h fallback.h util.h common.h halloc.h
|
||||
highlight.o: signal.h config.h fallback.h util.h wutil.h highlight.h
|
||||
highlight.o: config.h signal.h fallback.h util.h wutil.h highlight.h
|
||||
highlight.o: tokenizer.h proc.h io.h parser.h event.h parse_util.h builtin.h
|
||||
highlight.o: function.h env.h expand.h sanity.h common.h complete.h output.h
|
||||
highlight.o: halloc.h halloc_util.h
|
||||
history.o: config.h fallback.h util.h wutil.h history.h common.h reader.h
|
||||
history.o: env.h sanity.h signal.h
|
||||
highlight.o: halloc.h halloc_util.h wildcard.h path.h
|
||||
history2.o: config.h fallback.h util.h wutil.h history.h common.h halloc.h
|
||||
history2.o: halloc_util.h intern.h path.h
|
||||
history.o: config.h fallback.h util.h wutil.h history.h common.h halloc.h
|
||||
history.o: halloc_util.h intern.h path.h signal.h
|
||||
input.o: config.h signal.h fallback.h util.h wutil.h reader.h proc.h io.h
|
||||
input.o: common.h sanity.h input_common.h input.h parser.h event.h env.h
|
||||
input.o: expand.h output.h intern.h
|
||||
@@ -705,30 +990,36 @@ input_common.o: env_universal.h env_universal_common.h
|
||||
intern.o: config.h fallback.h util.h wutil.h common.h intern.h
|
||||
io.o: config.h fallback.h util.h wutil.h exec.h proc.h io.h common.h halloc.h
|
||||
key_reader.o: config.h fallback.h input_common.h
|
||||
kill.o: signal.h config.h fallback.h util.h wutil.h kill.h proc.h io.h
|
||||
kill.o: sanity.h common.h env.h exec.h parser.h event.h halloc.h
|
||||
kill.o: config.h signal.h fallback.h util.h wutil.h kill.h proc.h io.h
|
||||
kill.o: sanity.h common.h env.h exec.h halloc.h path.h
|
||||
main.o: config.h signal.h fallback.h util.h common.h reader.h builtin.h
|
||||
main.o: function.h complete.h wutil.h env.h sanity.h proc.h io.h parser.h
|
||||
main.o: event.h expand.h intern.h exec.h output.h halloc_util.h history.h
|
||||
main.o: event.h expand.h intern.h exec.h output.h halloc.h halloc_util.h
|
||||
main.o: history.h path.h
|
||||
mimedb.o: config.h xdgmime.h fallback.h util.h
|
||||
output.o: config.h signal.h fallback.h util.h wutil.h expand.h common.h
|
||||
output.o: output.h halloc_util.h highlight.h
|
||||
parser.o: signal.h config.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
parser.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
parser.o: parser.h event.h tokenizer.h exec.h wildcard.h function.h builtin.h
|
||||
parser.o: env.h expand.h reader.h sanity.h env_universal.h
|
||||
parser.o: env_universal_common.h intern.h parse_util.h halloc.h halloc_util.h
|
||||
parser.o: path.h
|
||||
parse_util.o: config.h fallback.h util.h wutil.h common.h tokenizer.h
|
||||
parse_util.o: parse_util.h expand.h intern.h exec.h proc.h io.h env.h
|
||||
parse_util.o: wildcard.h halloc_util.h
|
||||
path.o: config.h fallback.h util.h common.h env.h wutil.h halloc.h
|
||||
path.o: halloc_util.h path.h expand.h
|
||||
proc.o: config.h signal.h fallback.h util.h wutil.h proc.h io.h common.h
|
||||
proc.o: reader.h sanity.h env.h parser.h event.h halloc.h halloc_util.h
|
||||
proc.o: output.h
|
||||
reader.o: config.h signal.h fallback.h util.h wutil.h highlight.h reader.h
|
||||
reader.o: proc.h io.h parser.h event.h complete.h history.h common.h sanity.h
|
||||
reader.o: env.h exec.h expand.h tokenizer.h kill.h input_common.h input.h
|
||||
reader.o: function.h output.h parse_util.h
|
||||
sanity.o: signal.h config.h fallback.h util.h common.h sanity.h proc.h io.h
|
||||
reader.o: function.h output.h screen.h parse_util.h
|
||||
sanity.o: config.h signal.h fallback.h util.h common.h sanity.h proc.h io.h
|
||||
sanity.o: history.h reader.h kill.h wutil.h
|
||||
screen.o: config.h fallback.h common.h util.h wutil.h output.h highlight.h
|
||||
screen.o: screen.h
|
||||
set_color.o: config.h fallback.h
|
||||
signal.o: config.h signal.h common.h util.h fallback.h wutil.h event.h
|
||||
signal.o: reader.h proc.h io.h
|
||||
|
||||
317
builtin.c
317
builtin.c
@@ -13,7 +13,7 @@
|
||||
|
||||
3). Create a file doc_src/NAME.txt, containing the manual for the builtin in Doxygen-format. Check the other builtin manuals for proper syntax.
|
||||
|
||||
4). Add an entry to the BUILTIN_DOC_SRC variable of Makefile.in. Note that the entries should be sorted alphabetically!
|
||||
4). Add an entry to the BUILTIN_DOC_SRC variable of Makefile.in.
|
||||
|
||||
5). Add an entry to the manual at the builtin-overview subsection of doc_src/doc.hdr. Note that the entries should be sorted alphabetically!
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "halloc_util.h"
|
||||
#include "parse_util.h"
|
||||
#include "expand.h"
|
||||
#include "path.h"
|
||||
|
||||
|
||||
|
||||
@@ -214,15 +215,17 @@ static void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
|
||||
|
||||
if( is_interactive && !builtin_out_redirect && b==sb_err)
|
||||
{
|
||||
|
||||
/* Interactive mode help to screen - only print synopsis if the rest won't fit */
|
||||
|
||||
int screen_height, lines;
|
||||
|
||||
|
||||
screen_height = common_get_height();
|
||||
lines = count_char( str, L'\n' );
|
||||
if( lines > 2*screen_height/3 )
|
||||
{
|
||||
wchar_t *pos;
|
||||
int cut=0;
|
||||
|
||||
/* Find first empty line */
|
||||
for( pos=str; *pos; pos++ )
|
||||
@@ -246,9 +249,16 @@ static void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
|
||||
if( is_empty )
|
||||
{
|
||||
*(pos+1)=L'\0';
|
||||
cut = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !cut )
|
||||
{
|
||||
*str = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +345,7 @@ static int builtin_bind( wchar_t **argv )
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case 'M':
|
||||
input_set_mode( woptarg );
|
||||
@@ -348,7 +358,7 @@ static int builtin_bind( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -430,7 +440,7 @@ static int builtin_block( wchar_t **argv )
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
@@ -450,7 +460,7 @@ static int builtin_block( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -461,13 +471,13 @@ static int builtin_block( wchar_t **argv )
|
||||
if( scope != UNSET )
|
||||
{
|
||||
sb_printf( sb_err, _( L"%ls: Can not specify scope when removing block\n" ), argv[0] );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if( !global_event_block )
|
||||
{
|
||||
sb_printf( sb_err, _( L"%ls: No blocks defined\n" ), argv[0] );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
event_block_t *eb = global_event_block;
|
||||
@@ -571,7 +581,7 @@ static int builtin_builtin( wchar_t **argv )
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
@@ -583,7 +593,7 @@ static int builtin_builtin( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -660,7 +670,7 @@ static int builtin_generic( wchar_t **argv )
|
||||
argv[0],
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
@@ -669,19 +679,19 @@ static int builtin_generic( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
Output a definition of the specified function to the sb_out
|
||||
Output a definition of the specified function to the specified
|
||||
stringbuffer. Used by the functions builtin.
|
||||
*/
|
||||
static void functions_def( wchar_t *name )
|
||||
static void functions_def( wchar_t *name, string_buffer_t *out )
|
||||
{
|
||||
const wchar_t *desc = function_get_desc( name );
|
||||
const wchar_t *def = function_get_definition(name);
|
||||
@@ -697,7 +707,7 @@ static void functions_def( wchar_t *name )
|
||||
al_init( &ev );
|
||||
event_get( &search, &ev );
|
||||
|
||||
sb_append2( sb_out,
|
||||
sb_append2( out,
|
||||
L"function ",
|
||||
name,
|
||||
(void *)0);
|
||||
@@ -706,7 +716,7 @@ static void functions_def( wchar_t *name )
|
||||
{
|
||||
wchar_t *esc_desc = escape( desc, 1 );
|
||||
|
||||
sb_append2( sb_out, L" --description ", esc_desc, (void *)0 );
|
||||
sb_append2( out, L" --description ", esc_desc, (void *)0 );
|
||||
free( esc_desc );
|
||||
}
|
||||
|
||||
@@ -717,22 +727,22 @@ static void functions_def( wchar_t *name )
|
||||
{
|
||||
case EVENT_SIGNAL:
|
||||
{
|
||||
sb_printf( sb_out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
|
||||
sb_printf( out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_VARIABLE:
|
||||
{
|
||||
sb_printf( sb_out, L" --on-variable %ls", next->param1.variable );
|
||||
sb_printf( out, L" --on-variable %ls", next->param1.variable );
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_EXIT:
|
||||
{
|
||||
if( next->param1.pid > 0 )
|
||||
sb_printf( sb_out, L" --on-process-exit %d", next->param1.pid );
|
||||
sb_printf( out, L" --on-process-exit %d", next->param1.pid );
|
||||
else
|
||||
sb_printf( sb_out, L" --on-job-exit %d", -next->param1.pid );
|
||||
sb_printf( out, L" --on-job-exit %d", -next->param1.pid );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -740,7 +750,7 @@ static void functions_def( wchar_t *name )
|
||||
{
|
||||
job_t *j = job_get( next->param1.job_id );
|
||||
if( j )
|
||||
sb_printf( sb_out, L" --on-job-exit %d", j->pgid );
|
||||
sb_printf( out, L" --on-job-exit %d", j->pgid );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -750,7 +760,7 @@ static void functions_def( wchar_t *name )
|
||||
|
||||
al_destroy( &ev );
|
||||
|
||||
sb_append2( sb_out,
|
||||
sb_append2( out,
|
||||
L"\n\t",
|
||||
def,
|
||||
L"\nend\n\n",
|
||||
@@ -835,7 +845,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case 'e':
|
||||
erase=1;
|
||||
@@ -864,7 +874,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -882,7 +892,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if( erase )
|
||||
@@ -903,7 +913,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
func = argv[woptind];
|
||||
if( !function_exists( func ) )
|
||||
@@ -915,7 +925,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
function_set_desc( func, desc );
|
||||
@@ -973,7 +983,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
|
||||
for( i=0; i<al_get_count( &names ); i++ )
|
||||
{
|
||||
functions_def( (wchar_t *)al_get( &names, i ) );
|
||||
functions_def( (wchar_t *)al_get( &names, i ), sb_out );
|
||||
}
|
||||
|
||||
al_destroy( &names );
|
||||
@@ -992,7 +1002,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
{
|
||||
if( !query )
|
||||
{
|
||||
functions_def( argv[i] );
|
||||
functions_def( argv[i], sb_out );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1004,21 +1014,14 @@ static int builtin_functions( wchar_t **argv )
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Test whether the specified string is a valid name for a keybinding
|
||||
*/
|
||||
static int wcsbindingname( wchar_t *str )
|
||||
typedef struct function_data
|
||||
{
|
||||
while( *str )
|
||||
{
|
||||
if( (!iswalnum(*str)) && (*str != L'-' ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return 1;
|
||||
wchar_t *name;
|
||||
wchar_t *description;
|
||||
array_list_t *events;
|
||||
}
|
||||
function_data_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -1030,7 +1033,6 @@ static int builtin_function( wchar_t **argv )
|
||||
int argc = builtin_count_args( argv );
|
||||
int res=0;
|
||||
wchar_t *desc=0;
|
||||
int is_binding=0;
|
||||
array_list_t *events;
|
||||
int i;
|
||||
|
||||
@@ -1046,10 +1048,6 @@ static int builtin_function( wchar_t **argv )
|
||||
L"description", required_argument, 0, 'd'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"key-binding", no_argument, 0, 'b'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"on-signal", required_argument, 0, 's'
|
||||
}
|
||||
@@ -1082,7 +1080,7 @@ static int builtin_function( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"bd:s:j:p:v:h",
|
||||
L"d:s:j:p:v:h",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -1097,7 +1095,6 @@ static int builtin_function( wchar_t **argv )
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
res = 1;
|
||||
break;
|
||||
@@ -1106,10 +1103,6 @@ static int builtin_function( wchar_t **argv )
|
||||
desc=woptarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
is_binding=1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
{
|
||||
int sig = wcs2sig( woptarg );
|
||||
@@ -1241,7 +1234,7 @@ static int builtin_function( wchar_t **argv )
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
res = 1;
|
||||
break;
|
||||
|
||||
@@ -1259,7 +1252,7 @@ static int builtin_function( wchar_t **argv )
|
||||
argc-woptind );
|
||||
res=1;
|
||||
}
|
||||
else if( !(is_binding?wcsbindingname( argv[woptind] ) : !wcsvarname( argv[woptind] ) ))
|
||||
else if( wcsfuncname( argv[woptind] ) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Illegal function name '%ls'\n" ),
|
||||
@@ -1316,16 +1309,20 @@ static int builtin_function( wchar_t **argv )
|
||||
}
|
||||
else
|
||||
{
|
||||
current_block->param1.function_name=halloc_wcsdup( current_block, argv[woptind]);
|
||||
current_block->param2.function_description=desc?halloc_wcsdup( current_block, desc):0;
|
||||
current_block->param3.function_is_binding = is_binding;
|
||||
current_block->param4.function_events = events;
|
||||
function_data_t * d = halloc( current_block, sizeof( function_data_t ));
|
||||
|
||||
d->name=halloc_wcsdup( current_block, argv[woptind]);
|
||||
d->description=desc?halloc_wcsdup( current_block, desc):0;
|
||||
d->events = events;
|
||||
|
||||
for( i=0; i<al_get_count( events ); i++ )
|
||||
{
|
||||
event_t *e = (event_t *)al_get( events, i );
|
||||
e->function_name = current_block->param1.function_name;
|
||||
e->function_name = d->name;
|
||||
}
|
||||
|
||||
current_block->data = d;
|
||||
|
||||
}
|
||||
|
||||
current_block->tok_pos = parser_get_pos();
|
||||
@@ -1383,7 +1380,7 @@ static int builtin_random( wchar_t **argv )
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
@@ -1392,7 +1389,7 @@ static int builtin_random( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -1412,7 +1409,7 @@ static int builtin_random( wchar_t **argv )
|
||||
}
|
||||
lrand48_r( &seed_buffer, &res );
|
||||
|
||||
sb_printf( sb_out, L"%d\n", res%32767 );
|
||||
sb_printf( sb_out, L"%d\n", abs(res%32767) );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1430,7 +1427,7 @@ static int builtin_random( wchar_t **argv )
|
||||
argv[0],
|
||||
argv[woptind] );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
seeded=1;
|
||||
srand48_r( foo, &seed_buffer);
|
||||
@@ -1444,7 +1441,7 @@ static int builtin_random( wchar_t **argv )
|
||||
argv[0],
|
||||
argc-woptind );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1531,7 +1528,7 @@ static int builtin_read( wchar_t **argv )
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case L'x':
|
||||
place |= ENV_EXPORT;
|
||||
@@ -1562,7 +1559,7 @@ static int builtin_read( wchar_t **argv )
|
||||
case L'?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1576,7 +1573,7 @@ static int builtin_read( wchar_t **argv )
|
||||
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if( (place&ENV_LOCAL?1:0) + (place & ENV_GLOBAL?1:0) + (place & ENV_UNIVERSAL?1:0) > 1)
|
||||
@@ -1587,7 +1584,7 @@ static int builtin_read( wchar_t **argv )
|
||||
parser_current_line() );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1600,7 +1597,7 @@ static int builtin_read( wchar_t **argv )
|
||||
if( !wcslen( argv[i] ) )
|
||||
{
|
||||
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
for( src=argv[i]; *src; src++ )
|
||||
@@ -1609,7 +1606,7 @@ static int builtin_read( wchar_t **argv )
|
||||
{
|
||||
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, argv[0], *src );
|
||||
sb_append2(sb_err, parser_current_line(), L"\n", (void *)0 );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1815,7 +1812,7 @@ static int builtin_status( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"hjt",
|
||||
L"hj:t",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -1832,7 +1829,7 @@ static int builtin_status( wchar_t **argv )
|
||||
long_options[opt_index].name );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
@@ -1858,7 +1855,7 @@ static int builtin_status( wchar_t **argv )
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
|
||||
}
|
||||
|
||||
@@ -1986,7 +1983,7 @@ static int builtin_exit( wchar_t **argv )
|
||||
argv[0],
|
||||
argv[1] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1998,7 +1995,7 @@ static int builtin_exit( wchar_t **argv )
|
||||
argv[0] );
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2049,7 +2046,7 @@ static int builtin_cd( wchar_t **argv )
|
||||
else
|
||||
dir_in = argv[1];
|
||||
|
||||
dir = parser_cdpath_get( context, dir_in );
|
||||
dir = path_get_cdpath( context, dir_in );
|
||||
|
||||
if( !dir )
|
||||
{
|
||||
@@ -2110,13 +2107,13 @@ static int builtin_source( wchar_t ** argv )
|
||||
{
|
||||
sb_printf( sb_err, _( L"%ls: Expected at least one argument, got %d\n" ), argv[0], argc );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if( wstat(argv[1], &buf) == -1 )
|
||||
{
|
||||
builtin_wperror( L"stat" );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
if( !S_ISREG(buf.st_mode) )
|
||||
@@ -2124,7 +2121,7 @@ static int builtin_source( wchar_t ** argv )
|
||||
sb_printf( sb_err, _( L"%ls: '%ls' is not a file\n" ), argv[0], argv[1] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
if( ( fd = wopen( argv[1], O_RDONLY ) ) == -1 )
|
||||
{
|
||||
@@ -2219,8 +2216,8 @@ static int builtin_fg( wchar_t **argv )
|
||||
*/
|
||||
for( j=first_job; j; j=j->next )
|
||||
{
|
||||
if( j->constructed && (!job_is_completed(j)) &&
|
||||
( (job_is_stopped(j) || !j->fg) && (j->job_control) ) )
|
||||
if( job_get_flag( j, JOB_CONSTRUCTED ) && (!job_is_completed(j)) &&
|
||||
( (job_is_stopped(j) || (!job_get_flag(j, JOB_FOREGROUND)) ) && job_get_flag( j, JOB_CONTROL) ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2241,9 +2238,20 @@ static int builtin_fg( wchar_t **argv )
|
||||
since we want to know if this is an ambigous job
|
||||
specification or if this is an malformed job id
|
||||
*/
|
||||
int pid = wcstol( argv[1], 0, 10 );
|
||||
j = job_get_from_pid( pid );
|
||||
if( j != 0 )
|
||||
wchar_t *endptr;
|
||||
int pid;
|
||||
int found_job = 0;
|
||||
|
||||
errno = 0;
|
||||
pid = wcstol( argv[1], &endptr, 10 );
|
||||
if( !( *endptr || errno ) )
|
||||
{
|
||||
j = job_get_from_pid( pid );
|
||||
if( j )
|
||||
found_job = 1;
|
||||
}
|
||||
|
||||
if( found_job )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Ambiguous job\n" ),
|
||||
@@ -2256,6 +2264,7 @@ static int builtin_fg( wchar_t **argv )
|
||||
argv[0],
|
||||
argv[1] );
|
||||
}
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
j=0;
|
||||
@@ -2264,12 +2273,14 @@ static int builtin_fg( wchar_t **argv )
|
||||
else
|
||||
{
|
||||
wchar_t *end;
|
||||
int pid = abs(wcstol( argv[1], &end, 10 ));
|
||||
int pid;
|
||||
errno = 0;
|
||||
pid = abs(wcstol( argv[1], &end, 10 ));
|
||||
|
||||
if( *end )
|
||||
if( *end || errno )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Argument '%ls' is not a number\n" ),
|
||||
BUILTIN_ERR_NOT_NUMBER,
|
||||
argv[0],
|
||||
argv[1] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
@@ -2277,7 +2288,7 @@ static int builtin_fg( wchar_t **argv )
|
||||
else
|
||||
{
|
||||
j = job_get_from_pid( pid );
|
||||
if( !j || !j->constructed || job_is_completed( j ))
|
||||
if( !j || !job_get_flag( j, JOB_CONSTRUCTED ) || job_is_completed( j ))
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: No suitable job: %d\n" ),
|
||||
@@ -2286,7 +2297,7 @@ static int builtin_fg( wchar_t **argv )
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
j=0;
|
||||
}
|
||||
else if( !j->job_control )
|
||||
else if( !job_get_flag( j, JOB_CONTROL) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
|
||||
@@ -2328,7 +2339,7 @@ static int builtin_fg( wchar_t **argv )
|
||||
reader_write_title();
|
||||
|
||||
make_first( j );
|
||||
j->fg=1;
|
||||
job_set_flag( j, JOB_FOREGROUND, 1 );
|
||||
|
||||
job_continue( j, job_is_stopped(j) );
|
||||
}
|
||||
@@ -2347,9 +2358,9 @@ static int send_to_bg( job_t *j, const wchar_t *name )
|
||||
L"bg",
|
||||
name );
|
||||
builtin_print_help( L"bg", sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else if( !j->job_control )
|
||||
else if( !job_get_flag( j, JOB_CONTROL ) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
|
||||
@@ -2357,7 +2368,7 @@ static int send_to_bg( job_t *j, const wchar_t *name )
|
||||
j->job_id,
|
||||
j->command );
|
||||
builtin_print_help( L"bg", sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2367,7 +2378,7 @@ static int send_to_bg( job_t *j, const wchar_t *name )
|
||||
j->command );
|
||||
}
|
||||
make_first( j );
|
||||
j->fg=0;
|
||||
job_set_flag( j, JOB_FOREGROUND, 0 );
|
||||
job_continue( j, job_is_stopped(j) );
|
||||
return 0;
|
||||
}
|
||||
@@ -2385,7 +2396,7 @@ static int builtin_bg( wchar_t **argv )
|
||||
job_t *j;
|
||||
for( j=first_job; j; j=j->next )
|
||||
{
|
||||
if( job_is_stopped(j) && j->job_control && (!job_is_completed(j)) )
|
||||
if( job_is_stopped(j) && job_get_flag( j, JOB_CONTROL ) && (!job_is_completed(j)) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2427,15 +2438,15 @@ static int builtin_for( wchar_t **argv )
|
||||
if( argc < 3)
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Expected at least two arguments, got %d\n"),
|
||||
argc ,
|
||||
argv[0] );
|
||||
BUILTIN_FOR_ERR_COUNT,
|
||||
argv[0] ,
|
||||
argc );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
}
|
||||
else if ( wcsvarname(argv[1]) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: '%ls' is not a valid variable name\n" ),
|
||||
BUILTIN_FOR_ERR_NAME,
|
||||
argv[0],
|
||||
argv[1] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
@@ -2494,6 +2505,30 @@ static int builtin_begin( wchar_t **argv )
|
||||
return proc_get_last_status();
|
||||
}
|
||||
|
||||
/**
|
||||
Define the function specified by the function_data_t structure.
|
||||
*/
|
||||
static void builtin_end_add_function_def( function_data_t *d )
|
||||
{
|
||||
/**
|
||||
Copy the text from the beginning of the function
|
||||
until the end command and use as the new definition
|
||||
for the specified function
|
||||
*/
|
||||
|
||||
wchar_t *def = wcsndup( parser_get_buffer()+current_block->tok_pos,
|
||||
parser_get_job_pos()-current_block->tok_pos );
|
||||
|
||||
function_add( d->name,
|
||||
def,
|
||||
d->description,
|
||||
d->events );
|
||||
|
||||
free( def );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Builtin for ending a block of code, such as a for-loop or an if statement.
|
||||
@@ -2509,7 +2544,7 @@ static int builtin_end( wchar_t **argv )
|
||||
argv[0] );
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2574,21 +2609,21 @@ static int builtin_end( wchar_t **argv )
|
||||
|
||||
case FUNCTION_DEF:
|
||||
{
|
||||
/**
|
||||
Copy the text from the beginning of the function
|
||||
until the end command and use as the new definition
|
||||
for the specified function
|
||||
*/
|
||||
wchar_t *def = wcsndup( parser_get_buffer()+current_block->tok_pos,
|
||||
parser_get_job_pos()-current_block->tok_pos );
|
||||
|
||||
function_add( current_block->param1.function_name,
|
||||
def,
|
||||
current_block->param2.function_description,
|
||||
current_block->param4.function_events,
|
||||
current_block->param3.function_is_binding );
|
||||
function_data_t *d = (function_data_t *)current_block->data;
|
||||
|
||||
if( d )
|
||||
{
|
||||
builtin_end_add_function_def( d );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(0,
|
||||
_(L"%ls: Missing function definition information. This is a fish bug. If you can reproduce it, please file a bug report to %s."),
|
||||
argv[0],
|
||||
PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
free(def);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2619,7 +2654,7 @@ static int builtin_else( wchar_t **argv )
|
||||
_( L"%ls: Not inside of 'if' block\n" ),
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2654,7 +2689,7 @@ static int builtin_break_continue( wchar_t **argv )
|
||||
argv[1] );
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -2671,7 +2706,7 @@ static int builtin_break_continue( wchar_t **argv )
|
||||
_( L"%ls: Not inside of loop\n" ),
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
b = current_block;
|
||||
@@ -2712,7 +2747,7 @@ static int builtin_return( wchar_t **argv )
|
||||
argv[0],
|
||||
argv[1] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2721,7 +2756,7 @@ static int builtin_return( wchar_t **argv )
|
||||
_( L"%ls: Too many arguments\n" ),
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -2737,23 +2772,24 @@ static int builtin_return( wchar_t **argv )
|
||||
_( L"%ls: Not inside of function\n" ),
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
b = current_block;
|
||||
while( ( b->type != FUNCTION_CALL))
|
||||
{
|
||||
b->type = FAKE;
|
||||
b->skip=1;
|
||||
b = b->outer;
|
||||
}
|
||||
b->skip=1;
|
||||
// proc_set_last_status( status );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin for executing one of several blocks of commands depending on the value of an argument.
|
||||
Builtin for executing one of several blocks of commands depending
|
||||
on the value of an argument.
|
||||
*/
|
||||
static int builtin_switch( wchar_t **argv )
|
||||
{
|
||||
@@ -2778,51 +2814,52 @@ static int builtin_switch( wchar_t **argv )
|
||||
current_block->skip=1;
|
||||
current_block->param2.switch_taken=0;
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin used together with the switch builtin for conditional execution
|
||||
Builtin used together with the switch builtin for conditional
|
||||
execution
|
||||
*/
|
||||
static int builtin_case( wchar_t **argv )
|
||||
{
|
||||
int argc = builtin_count_args( argv );
|
||||
int i;
|
||||
wchar_t *unescaped=0;
|
||||
|
||||
|
||||
if( current_block->type != SWITCH )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: 'case' command while not in switch block\n" ),
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
current_block->skip = 1;
|
||||
|
||||
|
||||
if( current_block->param2.switch_taken )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for( i=1; i<argc; i++ )
|
||||
{
|
||||
free( unescaped );
|
||||
|
||||
int match;
|
||||
|
||||
unescaped = parse_util_unescape_wildcards( argv[i] );
|
||||
match = wildcard_match( current_block->param1.switch_value, unescaped );
|
||||
free( unescaped );
|
||||
|
||||
|
||||
if( wildcard_match( current_block->param1.switch_value, unescaped ) )
|
||||
if( match )
|
||||
{
|
||||
current_block->skip = 0;
|
||||
current_block->param2.switch_taken = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free( unescaped );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2838,15 +2875,15 @@ static int builtin_case( wchar_t **argv )
|
||||
const static builtin_data_t builtin_data[]=
|
||||
{
|
||||
{
|
||||
L"exit", &builtin_exit, N_( L"Exit the shell" )
|
||||
L"exit", &builtin_exit, N_( L"Exit the shell" )
|
||||
}
|
||||
,
|
||||
{
|
||||
L"block", &builtin_block, N_( L"Temporarily block delivery of events" )
|
||||
L"block", &builtin_block, N_( L"Temporarily block delivery of events" )
|
||||
}
|
||||
,
|
||||
{
|
||||
L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" )
|
||||
L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" )
|
||||
}
|
||||
,
|
||||
{
|
||||
@@ -3048,6 +3085,8 @@ int builtin_exists( wchar_t *cmd )
|
||||
*/
|
||||
static int internal_help( wchar_t *cmd )
|
||||
{
|
||||
CHECK( cmd, 0 );
|
||||
|
||||
if( wcscmp( cmd, L"for" ) == 0 ||
|
||||
wcscmp( cmd, L"while" ) == 0 ||
|
||||
wcscmp( cmd, L"function" ) == 0 ||
|
||||
|
||||
18
builtin.h
18
builtin.h
@@ -62,11 +62,29 @@ enum
|
||||
*/
|
||||
#define BUILTIN_FOR_ERR_IN _( L"%ls: Second argument must be 'in'\n" )
|
||||
|
||||
/**
|
||||
Error message for insufficient number of arguments
|
||||
*/
|
||||
#define BUILTIN_FOR_ERR_COUNT _( L"%ls: Expected at least two arguments, got %d\n")
|
||||
|
||||
#define BUILTIN_FOR_ERR_NAME _( L"%ls: '%ls' is not a valid variable name\n" )
|
||||
|
||||
/**
|
||||
Error message when too many arguments are supplied to a builtin
|
||||
*/
|
||||
#define BUILTIN_ERR_TOO_MANY_ARGUMENTS _( L"%ls: Too many arguments\n" )
|
||||
|
||||
/**
|
||||
Error message when block types mismatch in the end builtin, e.g. 'begin; end for'
|
||||
*/
|
||||
#define BUILTIN_END_BLOCK_MISMATCH _( L"%ls: Block mismatch: '%ls' vs. '%ls'\n" )
|
||||
|
||||
/**
|
||||
Error message for unknown block type in the end builtin, e.g. 'begin; end beggin'
|
||||
*/
|
||||
#define BUILTIN_END_BLOCK_UNKNOWN _( L"%ls: Unknown block type '%ls'\n" )
|
||||
|
||||
#define BUILTIN_ERR_NOT_NUMBER _( L"%ls: Argument '%ls' is not a number\n" )
|
||||
/**
|
||||
Stringbuffer used to represent standard output
|
||||
*/
|
||||
|
||||
@@ -52,15 +52,15 @@ enum
|
||||
}
|
||||
;
|
||||
|
||||
static wchar_t *current_buffer=0;
|
||||
static int current_cursor_pos = -1;
|
||||
|
||||
/**
|
||||
Returns the current commandline buffer.
|
||||
*/
|
||||
static const wchar_t *get_buffer()
|
||||
static wchar_t *get_buffer()
|
||||
{
|
||||
const wchar_t *buff = builtin_complete_get_temporary_buffer();
|
||||
if( !buff )
|
||||
buff = reader_get_buffer();
|
||||
return buff;
|
||||
return current_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +68,7 @@ static const wchar_t *get_buffer()
|
||||
*/
|
||||
static int get_cursor_pos()
|
||||
{
|
||||
const wchar_t *buff = builtin_complete_get_temporary_buffer();
|
||||
if( buff )
|
||||
return wcslen( buff );
|
||||
else
|
||||
return reader_get_cursor_pos();
|
||||
return current_cursor_pos;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +206,20 @@ static int builtin_commandline( wchar_t **argv )
|
||||
int function_mode = 0;
|
||||
|
||||
int tokenize = 0;
|
||||
|
||||
int cursor_mode = 0;
|
||||
wchar_t *begin, *end;
|
||||
|
||||
current_buffer = (wchar_t *)builtin_complete_get_temporary_buffer();
|
||||
if( current_buffer )
|
||||
{
|
||||
current_cursor_pos = wcslen( current_buffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
current_buffer = reader_get_buffer();
|
||||
current_cursor_pos = reader_get_cursor_pos();
|
||||
}
|
||||
|
||||
if( !get_buffer() )
|
||||
{
|
||||
@@ -272,6 +282,14 @@ static int builtin_commandline( wchar_t **argv )
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"input", required_argument, 0, 'I'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"cursor", no_argument, 0, 'C'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -282,7 +300,7 @@ static int builtin_commandline( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"aijpctwforh",
|
||||
L"aijpctwforhI:C",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -337,6 +355,15 @@ static int builtin_commandline( wchar_t **argv )
|
||||
tokenize=1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
current_buffer = woptarg;
|
||||
current_cursor_pos = wcslen( woptarg );
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
cursor_mode = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
@@ -354,16 +381,13 @@ static int builtin_commandline( wchar_t **argv )
|
||||
/*
|
||||
Check for invalid switch combinations
|
||||
*/
|
||||
if( buffer_part || cut_at_cursor || append_mode || tokenize )
|
||||
if( buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode )
|
||||
{
|
||||
sb_printf(sb_err,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0] );
|
||||
|
||||
sb_append2(sb_err,
|
||||
parser_current_line(),
|
||||
L"\n",
|
||||
(void *)0);
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -374,10 +398,6 @@ static int builtin_commandline( wchar_t **argv )
|
||||
BUILTIN_ERR_MISSING,
|
||||
argv[0] );
|
||||
|
||||
sb_append2( sb_err,
|
||||
parser_current_line(),
|
||||
L"\n",
|
||||
(void *)0 );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
@@ -386,7 +406,6 @@ static int builtin_commandline( wchar_t **argv )
|
||||
wint_t c = input_get_code( argv[i] );
|
||||
if( c != -1 )
|
||||
{
|
||||
// fwprintf( stderr, L"Add function %ls (%d)\n", argv[i], c );
|
||||
/*
|
||||
input_unreadch inserts the specified keypress or
|
||||
readline function at the top of the stack of unused
|
||||
@@ -396,15 +415,10 @@ static int builtin_commandline( wchar_t **argv )
|
||||
}
|
||||
else
|
||||
{
|
||||
// fwprintf( stderr, L"BLUR %ls %d\n", argv[i], c );
|
||||
sb_append2( sb_err,
|
||||
argv[0],
|
||||
L": Unknown readline function '",
|
||||
argv[i],
|
||||
L"'\n",
|
||||
parser_current_line(),
|
||||
L"\n",
|
||||
(void *)0 );
|
||||
sb_printf( sb_err,
|
||||
_(L"%ls: Unknown readline function '%ls'\n"),
|
||||
argv[0],
|
||||
argv[i] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
@@ -416,7 +430,7 @@ static int builtin_commandline( wchar_t **argv )
|
||||
/*
|
||||
Check for invalid switch combinations
|
||||
*/
|
||||
if( argc-woptind > 1 )
|
||||
if( cursor_mode && (argc-woptind > 1) )
|
||||
{
|
||||
|
||||
sb_append2( sb_err,
|
||||
@@ -427,9 +441,19 @@ static int builtin_commandline( wchar_t **argv )
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( (buffer_part || tokenize || cut_at_cursor) && cursor_mode )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0] );
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if( (tokenize || cut_at_cursor) && (argc-woptind) )
|
||||
{
|
||||
|
||||
sb_printf( sb_err,
|
||||
BUILTIN_ERR_COMBO2,
|
||||
argv[0],
|
||||
@@ -463,14 +487,44 @@ static int builtin_commandline( wchar_t **argv )
|
||||
{
|
||||
buffer_part = STRING_MODE;
|
||||
}
|
||||
|
||||
if( cursor_mode )
|
||||
{
|
||||
if( argc-woptind )
|
||||
{
|
||||
wchar_t *endptr;
|
||||
int new_pos;
|
||||
errno = 0;
|
||||
|
||||
new_pos = wcstol( argv[woptind], &endptr, 10 );
|
||||
if( *endptr || errno )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
BUILTIN_ERR_NOT_NUMBER,
|
||||
argv[0],
|
||||
argv[woptind] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
}
|
||||
|
||||
current_buffer = reader_get_buffer();
|
||||
new_pos = maxi( 0, mini( new_pos, wcslen( current_buffer ) ) );
|
||||
reader_set_buffer( current_buffer, new_pos );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_printf( sb_out, L"%d\n", reader_get_cursor_pos() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
wchar_t *begin, *end;
|
||||
}
|
||||
|
||||
|
||||
switch( buffer_part )
|
||||
{
|
||||
case STRING_MODE:
|
||||
{
|
||||
begin = (wchar_t *)get_buffer();
|
||||
begin = get_buffer();
|
||||
end = begin+wcslen(begin);
|
||||
break;
|
||||
}
|
||||
@@ -516,7 +570,28 @@ static int builtin_commandline( wchar_t **argv )
|
||||
case 1:
|
||||
{
|
||||
replace_part( begin, end, argv[woptind], append_mode );
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
string_buffer_t sb;
|
||||
int i;
|
||||
|
||||
sb_init( &sb );
|
||||
|
||||
sb_append( &sb, argv[woptind] );
|
||||
|
||||
for( i=woptind+1; i<argc; i++ )
|
||||
{
|
||||
sb_append( &sb, L"\n" );
|
||||
sb_append( &sb, argv[i] );
|
||||
}
|
||||
|
||||
replace_part( begin, end, (wchar_t *)sb.buff, append_mode );
|
||||
sb_destroy( &sb );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -489,14 +489,14 @@ static int builtin_complete( wchar_t **argv )
|
||||
{
|
||||
if( condition && wcslen( condition ) )
|
||||
{
|
||||
if( parser_test( condition, 0, 0 ) )
|
||||
if( parser_test( condition, 0, 0, 0 ) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
L"%ls: Condition '%ls' contained a syntax error\n",
|
||||
argv[0],
|
||||
condition );
|
||||
|
||||
parser_test( condition, sb_err, argv[0] );
|
||||
parser_test( condition, 0, sb_err, argv[0] );
|
||||
|
||||
res = 1;
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ static int builtin_jobs( wchar_t **argv )
|
||||
*/
|
||||
for( j=first_job; j; j=j->next )
|
||||
{
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
return 0;
|
||||
@@ -330,7 +330,7 @@ static int builtin_jobs( wchar_t **argv )
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
found = 1;
|
||||
|
||||
@@ -318,20 +318,20 @@ static int al_contains_long( array_list_t *list,
|
||||
*/
|
||||
static void erase_values(array_list_t *list, array_list_t *indexes)
|
||||
{
|
||||
int i;
|
||||
long i;
|
||||
array_list_t result;
|
||||
|
||||
al_init(&result);
|
||||
|
||||
for (i = 0; i < al_get_count(list); i++)
|
||||
{
|
||||
if (!al_contains_long(indexes, (long)i + 1))
|
||||
if (!al_contains_long(indexes, i + 1))
|
||||
{
|
||||
al_push(&result, al_get(list, i));
|
||||
}
|
||||
else
|
||||
{
|
||||
free((void *) al_get(list, i));
|
||||
free( (void *)al_get(list, i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ static void print_variables(int include_values, int esc, int scope)
|
||||
for( i = 0; i < al_get_count(&names); i++ )
|
||||
{
|
||||
wchar_t *key = (wchar_t *)al_get( &names, i );
|
||||
wchar_t *e_key = esc ? escape(key, 1) : wcsdup(key);
|
||||
wchar_t *e_key = esc ? escape(key, 0) : wcsdup(key);
|
||||
|
||||
sb_append(sb_out, e_key);
|
||||
|
||||
@@ -366,9 +366,32 @@ static void print_variables(int include_values, int esc, int scope)
|
||||
{
|
||||
wchar_t *value = env_get(key);
|
||||
wchar_t *e_value;
|
||||
e_value = esc ? expand_escape_variable(value) : wcsdup(value);
|
||||
sb_append2(sb_out, L" ", e_value, (void *)0);
|
||||
free(e_value);
|
||||
if( value )
|
||||
{
|
||||
int shorten = 0;
|
||||
|
||||
if( wcslen( value ) > 64 )
|
||||
{
|
||||
shorten = 1;
|
||||
value = wcsndup( value, 60 );
|
||||
if( !value )
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
}
|
||||
|
||||
e_value = esc ? expand_escape_variable(value) : wcsdup(value);
|
||||
|
||||
sb_append2(sb_out, L" ", e_value, (void *)0);
|
||||
free(e_value);
|
||||
|
||||
if( shorten )
|
||||
{
|
||||
sb_append(sb_out, L"\u2026");
|
||||
free( value );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sb_append(sb_out, L"\n");
|
||||
@@ -455,6 +478,8 @@ static int builtin_set( wchar_t **argv )
|
||||
int slice=0;
|
||||
int i;
|
||||
|
||||
wchar_t *bad_char;
|
||||
|
||||
|
||||
/* Parse options to obtain the requested operation and the modifiers */
|
||||
woptind = 0;
|
||||
@@ -599,6 +624,13 @@ static int builtin_set( wchar_t **argv )
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if( list )
|
||||
{
|
||||
/* Maybe we should issue an error if there are any other arguments? */
|
||||
print_variables(0, 0, scope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( woptind == argc )
|
||||
{
|
||||
/*
|
||||
@@ -623,13 +655,6 @@ static int builtin_set( wchar_t **argv )
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if( list )
|
||||
{
|
||||
/* Maybe we should issue an error if there are any other arguments? */
|
||||
print_variables(0, 0, scope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !(dest = wcsdup(argv[woptind])))
|
||||
{
|
||||
DIE_MEM();
|
||||
@@ -648,7 +673,15 @@ static int builtin_set( wchar_t **argv )
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if( (bad_char = wcsvarname( dest ) ) )
|
||||
{
|
||||
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, argv[0], *bad_char );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
free( dest );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( slice && erase && (scope != ENV_USER) )
|
||||
{
|
||||
free( dest );
|
||||
@@ -676,9 +709,9 @@ static int builtin_set( wchar_t **argv )
|
||||
al_init(&values);
|
||||
al_init(&indexes);
|
||||
al_init(&result);
|
||||
|
||||
|
||||
tokenize_variable_array( env_get(dest), &result );
|
||||
|
||||
|
||||
for( ; woptind<argc; woptind++ )
|
||||
{
|
||||
if( !parse_index( &indexes, argv[woptind], dest, al_get_count( &result ) ) )
|
||||
|
||||
236
common.c
236
common.c
@@ -296,7 +296,10 @@ char *wcs2str_internal( const wchar_t *in, char *out )
|
||||
|
||||
while( in[in_pos] )
|
||||
{
|
||||
if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
|
||||
if( in[in_pos] == INTERNAL_SEPARATOR )
|
||||
{
|
||||
}
|
||||
else if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
|
||||
( in[in_pos] < ENCODE_DIRECT_BASE+256) )
|
||||
{
|
||||
out[out_pos++] = in[in_pos]- ENCODE_DIRECT_BASE;
|
||||
@@ -307,7 +310,7 @@ char *wcs2str_internal( const wchar_t *in, char *out )
|
||||
|
||||
if( res == (size_t)(-1) )
|
||||
{
|
||||
debug( 1, L"Wide character has no narrow representation" );
|
||||
debug( 1, L"Wide character %d has no narrow representation", in[in_pos] );
|
||||
memset( &state, 0, sizeof(state) );
|
||||
}
|
||||
else
|
||||
@@ -405,19 +408,25 @@ wchar_t **strv2wcsv( const char **in )
|
||||
|
||||
}
|
||||
|
||||
wchar_t *wcsvarname( wchar_t *str )
|
||||
wchar_t *wcsvarname( const wchar_t *str )
|
||||
{
|
||||
while( *str )
|
||||
{
|
||||
if( (!iswalnum(*str)) && (*str != L'_' ) )
|
||||
{
|
||||
return str;
|
||||
return (wchar_t *)str;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
wchar_t *wcsfuncname( const wchar_t *str )
|
||||
{
|
||||
return wcschr( str, L'/' );
|
||||
}
|
||||
|
||||
|
||||
int wcsvarchr( wchar_t chr )
|
||||
{
|
||||
return ( (iswalnum(chr)) || (chr == L'_' ));
|
||||
@@ -813,64 +822,22 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
{
|
||||
switch( in[++in_pos] )
|
||||
{
|
||||
|
||||
/*
|
||||
A null character after a backslash is an
|
||||
error, return null
|
||||
*/
|
||||
case L'\0':
|
||||
{
|
||||
free(in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case L'n':
|
||||
{
|
||||
in[out_pos]=L'\n';
|
||||
break;
|
||||
}
|
||||
/*
|
||||
Numeric escape sequences. No prefix means
|
||||
octal escape, otherwise hexadecimal.
|
||||
*/
|
||||
|
||||
case L'r':
|
||||
{
|
||||
in[out_pos]=L'\r';
|
||||
break;
|
||||
}
|
||||
|
||||
case L't':
|
||||
{
|
||||
in[out_pos]=L'\t';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'b':
|
||||
{
|
||||
in[out_pos]=L'\b';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'a':
|
||||
{
|
||||
in[out_pos]=L'\a';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'f':
|
||||
{
|
||||
in[out_pos]=L'\f';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'v':
|
||||
{
|
||||
in[out_pos]=L'\v';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'e':
|
||||
{
|
||||
in[out_pos]=L'\x1b';
|
||||
break;
|
||||
}
|
||||
|
||||
case L'u':
|
||||
case L'U':
|
||||
case L'x':
|
||||
case L'X':
|
||||
case L'0':
|
||||
case L'1':
|
||||
case L'2':
|
||||
@@ -879,6 +846,10 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'u':
|
||||
case L'U':
|
||||
case L'x':
|
||||
case L'X':
|
||||
{
|
||||
int i;
|
||||
long long res=0;
|
||||
@@ -951,8 +922,107 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\a means bell (alert)
|
||||
*/
|
||||
case L'a':
|
||||
{
|
||||
in[out_pos]=L'\a';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\b means backspace
|
||||
*/
|
||||
case L'b':
|
||||
{
|
||||
in[out_pos]=L'\b';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\cX means control sequence X
|
||||
*/
|
||||
case L'c':
|
||||
{
|
||||
in_pos++;
|
||||
if( in[in_pos] >= L'a' &&
|
||||
in[in_pos] <= (L'a'+32) )
|
||||
{
|
||||
in[out_pos]=in[in_pos]-L'a'+1;
|
||||
}
|
||||
else if( in[in_pos] >= L'A' &&
|
||||
in[in_pos] <= (L'A'+32) )
|
||||
{
|
||||
in[out_pos]=in[in_pos]-L'A'+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(in);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
\e means escape
|
||||
*/
|
||||
case L'e':
|
||||
{
|
||||
in[out_pos]=L'\x1b';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\f means form feed
|
||||
*/
|
||||
case L'f':
|
||||
{
|
||||
in[out_pos]=L'\f';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\n means newline
|
||||
*/
|
||||
case L'n':
|
||||
{
|
||||
in[out_pos]=L'\n';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\r means carriage return
|
||||
*/
|
||||
case L'r':
|
||||
{
|
||||
in[out_pos]=L'\r';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\t means tab
|
||||
*/
|
||||
case L't':
|
||||
{
|
||||
in[out_pos]=L'\t';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
\v means vetrical tab
|
||||
*/
|
||||
case L'v':
|
||||
{
|
||||
in[out_pos]=L'\v';
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if( unescape_special )
|
||||
in[out_pos++] = INTERNAL_SEPARATOR;
|
||||
in[out_pos]=in[in_pos];
|
||||
break;
|
||||
}
|
||||
@@ -960,7 +1030,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( in[in_pos]){
|
||||
switch( in[in_pos])
|
||||
{
|
||||
case L'~':
|
||||
{
|
||||
if( unescape_special && (in_pos == 0) )
|
||||
@@ -1076,14 +1147,16 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
case L'\'':
|
||||
{
|
||||
mode = 1;
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
if( unescape_special )
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'\"':
|
||||
{
|
||||
mode = 2;
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
if( unescape_special )
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1108,6 +1181,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
{
|
||||
case '\\':
|
||||
case L'\'':
|
||||
case L'\n':
|
||||
{
|
||||
in[out_pos]=in[in_pos];
|
||||
break;
|
||||
@@ -1129,7 +1203,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
}
|
||||
if( c == L'\'' )
|
||||
{
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
if( unescape_special )
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
mode = 0;
|
||||
}
|
||||
else
|
||||
@@ -1150,7 +1225,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
case '"':
|
||||
{
|
||||
mode = 0;
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
if( unescape_special )
|
||||
in[out_pos] = INTERNAL_SEPARATOR;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1167,6 +1243,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
|
||||
case '\\':
|
||||
case L'$':
|
||||
case '"':
|
||||
case '\n':
|
||||
{
|
||||
in[out_pos]=in[in_pos];
|
||||
break;
|
||||
@@ -1486,3 +1563,42 @@ void tokenize_variable_array( const wchar_t *val, array_list_t *out )
|
||||
}
|
||||
|
||||
|
||||
int create_directory( wchar_t *d )
|
||||
{
|
||||
int ok = 0;
|
||||
struct stat buf;
|
||||
int stat_res = 0;
|
||||
|
||||
while( (stat_res = wstat(d, &buf ) ) != 0 )
|
||||
{
|
||||
if( errno != EAGAIN )
|
||||
break;
|
||||
}
|
||||
|
||||
if( stat_res == 0 )
|
||||
{
|
||||
if( S_ISDIR( buf.st_mode ) )
|
||||
{
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( errno == ENOENT )
|
||||
{
|
||||
wchar_t *dir = wcsdup( d );
|
||||
dir = wdirname( dir );
|
||||
if( !create_directory( dir ) )
|
||||
{
|
||||
if( !wmkdir( d, 0700 ) )
|
||||
{
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
}
|
||||
|
||||
return ok?0:-1;
|
||||
}
|
||||
|
||||
|
||||
70
common.h
70
common.h
@@ -52,7 +52,8 @@ extern struct termios shell_modes;
|
||||
extern wchar_t ellipsis_char;
|
||||
|
||||
/**
|
||||
The verbosity of fish
|
||||
The verbosity level of fish. If a call to debug has a severity
|
||||
level higher than \c debug_level, it will not be printed.
|
||||
*/
|
||||
extern int debug_level;
|
||||
|
||||
@@ -73,28 +74,54 @@ extern wchar_t *program_name;
|
||||
failiure, the current function is ended at once. The second
|
||||
parameter is the exit status of the current function on failiure.
|
||||
*/
|
||||
#define CHECK( arg, retval ) \
|
||||
#define CHECK( arg, retval ) \
|
||||
if( !(arg) ) \
|
||||
{ \
|
||||
debug( 1, \
|
||||
L"function %s called with null value for argument %s. " \
|
||||
L"This is a bug. " \
|
||||
L"If you can reproduce it, please send a bug report to %s.", \
|
||||
_( L"function %s called with null value for argument %s. " \
|
||||
L"This is a bug. " \
|
||||
L"If you can reproduce it, please send a bug report to %s." ), \
|
||||
__func__, \
|
||||
#arg, \
|
||||
PACKAGE_BUGREPORT ); \
|
||||
return retval; \
|
||||
} \
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Exit program at once, leaving an error message about running out of memory
|
||||
*/
|
||||
#define DIE_MEM() \
|
||||
#define DIE_MEM() \
|
||||
{ \
|
||||
fwprintf( stderr, L"fish: Out of memory on line %d of file %s, shutting down fish\n", __LINE__, __FILE__ ); \
|
||||
fwprintf( stderr, \
|
||||
L"fish: Out of memory on line %d of file %s, shutting down fish\n", \
|
||||
__LINE__, \
|
||||
__FILE__ ); \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
Cause fish to crash. This should only be usd for debugging.
|
||||
*/
|
||||
#define CRASH() \
|
||||
{ \
|
||||
int *n = 0; \
|
||||
*n = 1; \
|
||||
}
|
||||
|
||||
/**
|
||||
Check if signals are blocked
|
||||
*/
|
||||
#define CHECK_BLOCK( retval ) \
|
||||
if( signal_is_blocked() ) \
|
||||
{ \
|
||||
debug( 0, \
|
||||
L"function %s called while blocking signals. " \
|
||||
L"This is a bug. " \
|
||||
L"If you can reproduce it, please send a bug report to %s.", \
|
||||
__func__, \
|
||||
PACKAGE_BUGREPORT ); \
|
||||
return retval; \
|
||||
}
|
||||
|
||||
/**
|
||||
Shorthand for wgettext call
|
||||
@@ -106,6 +133,7 @@ extern wchar_t *program_name;
|
||||
*/
|
||||
#define N_(wstr) wstr
|
||||
|
||||
|
||||
/**
|
||||
Take an array_list_t containing wide strings and converts them to a
|
||||
single null-terminated wchar_t **. The array is allocated using
|
||||
@@ -193,7 +221,7 @@ wchar_t *wcsdupcat( const wchar_t *a, const wchar_t *b );
|
||||
Returns a newly allocated concatenation of the specified wide
|
||||
character strings. The last argument must be a null pointer.
|
||||
*/
|
||||
wchar_t *wcsdupcat2( const wchar_t *a, ... );
|
||||
__sentinel wchar_t *wcsdupcat2( const wchar_t *a, ... );
|
||||
|
||||
/**
|
||||
Test if the given string is a valid variable name
|
||||
@@ -206,7 +234,16 @@ wchar_t *wcsdupcat2( const wchar_t *a, ... );
|
||||
\return null if this is a valid name, and a pointer to the first invalid character otherwise
|
||||
*/
|
||||
|
||||
wchar_t *wcsvarname( wchar_t *str );
|
||||
wchar_t *wcsvarname( const wchar_t *str );
|
||||
|
||||
|
||||
/**
|
||||
Test if the given string is a valid function name.
|
||||
|
||||
\return null if this is a valid name, and a pointer to the first invalid character otherwise
|
||||
*/
|
||||
|
||||
wchar_t *wcsfuncname( const wchar_t *str );
|
||||
|
||||
/**
|
||||
Test if the given string is valid in a variable name
|
||||
@@ -256,7 +293,7 @@ const wchar_t *wsetlocale( int category, const wchar_t *locale );
|
||||
|
||||
\return zero is needle is not found, of if needle is null, non-zero otherwise
|
||||
*/
|
||||
int contains_str( const wchar_t *needle, ... );
|
||||
__sentinel int contains_str( const wchar_t *needle, ... );
|
||||
|
||||
/**
|
||||
Call read while blocking the SIGCHLD signal. Should only be called
|
||||
@@ -358,5 +395,12 @@ void write_screen( const wchar_t *msg, string_buffer_t *buff );
|
||||
void tokenize_variable_array( const wchar_t *val, array_list_t *out );
|
||||
|
||||
|
||||
/**
|
||||
Make sure the specified direcotry exists. If no, try to create it.
|
||||
|
||||
\return 0 if the directory exists, -1 otherwise.
|
||||
*/
|
||||
int create_directory( wchar_t *d );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
406
complete.c
406
complete.c
@@ -45,6 +45,7 @@
|
||||
#include "halloc.h"
|
||||
#include "halloc_util.h"
|
||||
#include "wutil.h"
|
||||
#include "path.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -194,7 +195,7 @@ typedef struct complete_entry_opt
|
||||
/** Next option in the linked list */
|
||||
struct complete_entry_opt *next;
|
||||
}
|
||||
complete_entry_opt;
|
||||
complete_entry_opt_t;
|
||||
|
||||
/**
|
||||
Struct describing a command completion
|
||||
@@ -209,16 +210,16 @@ typedef struct complete_entry
|
||||
/** String containing all short option characters */
|
||||
wchar_t *short_opt_str;
|
||||
/** Linked list of all options */
|
||||
complete_entry_opt *first_option;
|
||||
complete_entry_opt_t *first_option;
|
||||
/** Next command completion in the linked list */
|
||||
struct complete_entry *next;
|
||||
/** True if no other options than the ones supplied are possible */
|
||||
int authorative;
|
||||
}
|
||||
complete_entry;
|
||||
complete_entry_t;
|
||||
|
||||
/** First node in the linked list of all completion entries */
|
||||
static complete_entry *first_entry=0;
|
||||
static complete_entry_t *first_entry=0;
|
||||
|
||||
/** Hashtable containing all descriptions that describe an executable */
|
||||
static hash_table_t *suffix_hash=0;
|
||||
@@ -235,7 +236,7 @@ static hash_table_t *condition_cache=0;
|
||||
static string_buffer_t *get_desc_buff=0;
|
||||
|
||||
|
||||
static void complete_free_entry( complete_entry *c );
|
||||
static void complete_free_entry( complete_entry_t *c );
|
||||
static void clear_hash_entry( void *key, void *data );
|
||||
|
||||
|
||||
@@ -244,7 +245,7 @@ static void clear_hash_entry( void *key, void *data );
|
||||
*/
|
||||
static void complete_destroy()
|
||||
{
|
||||
complete_entry *i=first_entry, *prev;
|
||||
complete_entry_t *i=first_entry, *prev;
|
||||
|
||||
while( i )
|
||||
{
|
||||
@@ -346,9 +347,9 @@ static int condition_test( const wchar_t *condition )
|
||||
|
||||
|
||||
/**
|
||||
Recursively free all complete_entry_opt structs and their contents
|
||||
Recursively free all complete_entry_opt_t structs and their contents
|
||||
*/
|
||||
static void complete_free_opt_recursive( complete_entry_opt *o )
|
||||
static void complete_free_opt_recursive( complete_entry_opt_t *o )
|
||||
{
|
||||
if( o->next != 0 )
|
||||
complete_free_opt_recursive( o->next );
|
||||
@@ -356,9 +357,9 @@ static void complete_free_opt_recursive( complete_entry_opt *o )
|
||||
}
|
||||
|
||||
/**
|
||||
Free a complete_entry and its contents
|
||||
Free a complete_entry_t and its contents
|
||||
*/
|
||||
static void complete_free_entry( complete_entry *c )
|
||||
static void complete_free_entry( complete_entry_t *c )
|
||||
{
|
||||
// free( c->cmd );
|
||||
free( c->short_opt_str );
|
||||
@@ -378,10 +379,10 @@ static void clear_hash_entry( void *key, void *data )
|
||||
/**
|
||||
Search for an exactly matching completion entry
|
||||
*/
|
||||
static complete_entry *complete_find_exact_entry( const wchar_t *cmd,
|
||||
static complete_entry_t *complete_find_exact_entry( const wchar_t *cmd,
|
||||
const int cmd_type )
|
||||
{
|
||||
complete_entry *i;
|
||||
complete_entry_t *i;
|
||||
for( i=first_entry; i; i=i->next )
|
||||
{
|
||||
if( ( wcscmp(cmd, i->cmd)==0) && ( cmd_type == i->cmd_type ))
|
||||
@@ -403,18 +404,18 @@ void complete_add( const wchar_t *cmd,
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc )
|
||||
{
|
||||
complete_entry *c;
|
||||
complete_entry_opt *opt;
|
||||
complete_entry_t *c;
|
||||
complete_entry_opt_t *opt;
|
||||
|
||||
CHECK( cmd, );
|
||||
|
||||
|
||||
complete_init();
|
||||
|
||||
c = complete_find_exact_entry( cmd, cmd_type );
|
||||
|
||||
if( c == 0 )
|
||||
{
|
||||
if( !(c = malloc( sizeof(complete_entry) )))
|
||||
if( !(c = malloc( sizeof(complete_entry_t) )))
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
@@ -429,7 +430,7 @@ void complete_add( const wchar_t *cmd,
|
||||
c->short_opt_str = wcsdup(L"");
|
||||
}
|
||||
|
||||
if( !(opt = malloc( sizeof( complete_entry_opt ) )))
|
||||
if( !(opt = malloc( sizeof( complete_entry_opt_t ) )))
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
@@ -474,7 +475,7 @@ void complete_remove( const wchar_t *cmd,
|
||||
wchar_t short_opt,
|
||||
const wchar_t *long_opt )
|
||||
{
|
||||
complete_entry *e, *eprev=0, *enext=0;
|
||||
complete_entry_t *e, *eprev=0, *enext=0;
|
||||
|
||||
CHECK( cmd, );
|
||||
|
||||
@@ -485,7 +486,7 @@ void complete_remove( const wchar_t *cmd,
|
||||
if( (cmd_type == e->cmd_type ) &&
|
||||
( wcscmp( cmd, e->cmd) == 0 ) )
|
||||
{
|
||||
complete_entry_opt *o, *oprev=0, *onext=0;
|
||||
complete_entry_opt_t *o, *oprev=0, *onext=0;
|
||||
|
||||
if(( short_opt == 0 ) && (long_opt == 0 ) )
|
||||
{
|
||||
@@ -581,14 +582,14 @@ static void parse_cmd_string( void *context,
|
||||
wchar_t *cmd, *path;
|
||||
|
||||
/* Get the path of the command */
|
||||
path = parser_get_filename( context, str );
|
||||
path = path_get_path( context, str );
|
||||
if( path == 0 )
|
||||
{
|
||||
/**
|
||||
Use the empty string as the 'path' for commands that can
|
||||
not be found.
|
||||
*/
|
||||
path = wcsdup(L"");
|
||||
path = halloc_wcsdup( context, L"");
|
||||
}
|
||||
|
||||
/* Make sure the path is not included in the command */
|
||||
@@ -610,8 +611,8 @@ int complete_is_valid_option( const wchar_t *str,
|
||||
const wchar_t *opt,
|
||||
array_list_t *errors )
|
||||
{
|
||||
complete_entry *i;
|
||||
complete_entry_opt *o;
|
||||
complete_entry_t *i;
|
||||
complete_entry_opt_t *o;
|
||||
wchar_t *cmd, *path;
|
||||
int found_match = 0;
|
||||
int authorative = 1;
|
||||
@@ -815,7 +816,7 @@ int complete_is_valid_option( const wchar_t *str,
|
||||
str[0] = opt[j];
|
||||
str[1]=0;
|
||||
al_push( errors,
|
||||
wcsdupcat2(_( L"Unknown option: " ), L"'", str, L"'", 0) );
|
||||
wcsdupcat2(_( L"Unknown option: " ), L"'", str, L"'", (void *)0) );
|
||||
}
|
||||
|
||||
opt_found = 0;
|
||||
@@ -833,12 +834,12 @@ int complete_is_valid_option( const wchar_t *str,
|
||||
if( hash_get_count( &gnu_match_hash )==0)
|
||||
{
|
||||
al_push( errors,
|
||||
wcsdupcat2( _(L"Unknown option: "), L"'", opt, L"\'", 0) );
|
||||
wcsdupcat2( _(L"Unknown option: "), L"'", opt, L"\'", (void *)0) );
|
||||
}
|
||||
else
|
||||
{
|
||||
al_push( errors,
|
||||
wcsdupcat2( _(L"Multiple matches for option: "), L"'", opt, L"\'", 0) );
|
||||
wcsdupcat2( _(L"Multiple matches for option: "), L"'", opt, L"\'", (void *)0) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -908,24 +909,26 @@ static const wchar_t *complete_get_desc_suffix( const wchar_t *suff_orig )
|
||||
array_list_t l;
|
||||
al_init( &l );
|
||||
|
||||
exec_subshell( cmd, &l );
|
||||
free(cmd);
|
||||
|
||||
if( al_get_count( &l )>0 )
|
||||
if( exec_subshell( cmd, &l ) != -1 )
|
||||
{
|
||||
wchar_t *ln = (wchar_t *)al_get(&l, 0 );
|
||||
if( wcscmp( ln, L"unknown" ) != 0 )
|
||||
|
||||
if( al_get_count( &l )>0 )
|
||||
{
|
||||
desc = wcsdup( ln);
|
||||
/*
|
||||
I have decided I prefer to have the description
|
||||
begin in uppercase and the whole universe will just
|
||||
have to accept it. Hah!
|
||||
*/
|
||||
desc[0]=towupper(desc[0]);
|
||||
wchar_t *ln = (wchar_t *)al_get(&l, 0 );
|
||||
if( wcscmp( ln, L"unknown" ) != 0 )
|
||||
{
|
||||
desc = wcsdup( ln);
|
||||
/*
|
||||
I have decided I prefer to have the description
|
||||
begin in uppercase and the whole universe will just
|
||||
have to accept it. Hah!
|
||||
*/
|
||||
desc[0]=towupper(desc[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(cmd);
|
||||
al_foreach( &l, &free );
|
||||
al_destroy( &l );
|
||||
}
|
||||
@@ -1154,78 +1157,82 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp )
|
||||
systems with a large set of manuals, but it should be ok
|
||||
since apropos is only called once.
|
||||
*/
|
||||
exec_subshell( lookup_cmd, &list );
|
||||
if( exec_subshell( lookup_cmd, &list ) != -1 )
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
Then discard anything that is not a possible completion and put
|
||||
the result into a hashtable with the completion as key and the
|
||||
description as value.
|
||||
|
||||
Should be reasonably fast, since no memory allocations are needed.
|
||||
*/
|
||||
for( i=0; i<al_get_count( &list); i++ )
|
||||
{
|
||||
wchar_t *el = (wchar_t *)al_get( &list, i );
|
||||
wchar_t *key, *key_end, *val_begin;
|
||||
key = el+wcslen(cmd);
|
||||
|
||||
if( !el )
|
||||
continue;
|
||||
|
||||
key_end = wcschr( el, L'\t' );
|
||||
if( !key_end )
|
||||
continue;
|
||||
|
||||
*key_end = 0;
|
||||
val_begin = key_end+1;
|
||||
|
||||
/*
|
||||
And once again I make sure the first character is uppercased
|
||||
because I like it that way, and I get to decide these
|
||||
things.
|
||||
Then discard anything that is not a possible completion and put
|
||||
the result into a hashtable with the completion as key and the
|
||||
description as value.
|
||||
|
||||
Should be reasonably fast, since no memory allocations are needed.
|
||||
*/
|
||||
val_begin[0]=towupper(val_begin[0]);
|
||||
for( i=0; i<al_get_count( &list); i++ )
|
||||
{
|
||||
wchar_t *el = (wchar_t *)al_get( &list, i );
|
||||
wchar_t *key, *key_end, *val_begin;
|
||||
|
||||
hash_put( &lookup, key, val_begin );
|
||||
}
|
||||
if( !el )
|
||||
continue;
|
||||
|
||||
/*
|
||||
Then do a lookup on every completion and if a match is found,
|
||||
change to the new description.
|
||||
key = el+wcslen(cmd_start);
|
||||
key_end = wcschr( el, L'\t' );
|
||||
|
||||
This needs to do a reallocation for every description added, but
|
||||
there shouldn't be that many completions, so it should be ok.
|
||||
*/
|
||||
for( i=0; i<al_get_count(comp); i++ )
|
||||
{
|
||||
wchar_t *el = (wchar_t *)al_get( comp, i );
|
||||
wchar_t *cmd_end = wcschr( el,
|
||||
COMPLETE_SEP );
|
||||
wchar_t *new_desc;
|
||||
|
||||
if( cmd_end )
|
||||
*cmd_end = 0;
|
||||
|
||||
new_desc = (wchar_t *)hash_get( &lookup,
|
||||
el );
|
||||
|
||||
if( new_desc )
|
||||
{
|
||||
wchar_t *new_el = wcsdupcat2( el,
|
||||
COMPLETE_SEP_STR,
|
||||
new_desc,
|
||||
0 );
|
||||
|
||||
al_set( comp, i, new_el );
|
||||
free( el );
|
||||
if( !key_end )
|
||||
continue;
|
||||
|
||||
*key_end = 0;
|
||||
val_begin = key_end+1;
|
||||
|
||||
/*
|
||||
And once again I make sure the first character is uppercased
|
||||
because I like it that way, and I get to decide these
|
||||
things.
|
||||
*/
|
||||
val_begin[0]=towupper(val_begin[0]);
|
||||
|
||||
hash_put( &lookup, key, val_begin );
|
||||
}
|
||||
else
|
||||
|
||||
/*
|
||||
Then do a lookup on every completion and if a match is found,
|
||||
change to the new description.
|
||||
|
||||
This needs to do a reallocation for every description added, but
|
||||
there shouldn't be that many completions, so it should be ok.
|
||||
*/
|
||||
for( i=0; i<al_get_count(comp); i++ )
|
||||
{
|
||||
wchar_t *el = (wchar_t *)al_get( comp, i );
|
||||
wchar_t *cmd_end = wcschr( el,
|
||||
COMPLETE_SEP );
|
||||
wchar_t *new_desc;
|
||||
|
||||
if( cmd_end )
|
||||
*cmd_end = COMPLETE_SEP;
|
||||
*cmd_end = 0;
|
||||
|
||||
new_desc = (wchar_t *)hash_get( &lookup,
|
||||
el );
|
||||
|
||||
if( new_desc )
|
||||
{
|
||||
wchar_t *new_el = wcsdupcat2( el,
|
||||
COMPLETE_SEP_STR,
|
||||
new_desc,
|
||||
(void *)0 );
|
||||
|
||||
al_set( comp, i, new_el );
|
||||
free( el );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cmd_end )
|
||||
*cmd_end = COMPLETE_SEP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hash_destroy( &lookup );
|
||||
al_foreach( &list,
|
||||
&free );
|
||||
@@ -1270,9 +1277,11 @@ static void complete_cmd( const wchar_t *cmd,
|
||||
|
||||
wchar_t *cdpath = env_get(L"CDPATH");
|
||||
wchar_t *cdpath_cpy = wcsdup( cdpath?cdpath:L"." );
|
||||
int prev_count = al_get_count( comp );
|
||||
|
||||
if( (wcschr( cmd, L'/') != 0) || (cmd[0] == L'~' ) )
|
||||
{
|
||||
|
||||
array_list_t tmp;
|
||||
al_init( &tmp );
|
||||
|
||||
@@ -1281,47 +1290,57 @@ static void complete_cmd( const wchar_t *cmd,
|
||||
comp,
|
||||
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
complete_cmd_desc( cmd, comp );
|
||||
if( al_get_count( comp ) > prev_count )
|
||||
{
|
||||
complete_cmd_desc( cmd, comp );
|
||||
}
|
||||
}
|
||||
al_destroy( &tmp );
|
||||
}
|
||||
else
|
||||
{
|
||||
path = env_get(L"PATH");
|
||||
path_cpy = wcsdup( path );
|
||||
|
||||
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
|
||||
nxt_path != 0;
|
||||
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
|
||||
if( path )
|
||||
{
|
||||
nxt_completion = wcsdupcat2( nxt_path,
|
||||
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
|
||||
cmd,
|
||||
0 );
|
||||
if( ! nxt_completion )
|
||||
continue;
|
||||
|
||||
al_init( &tmp );
|
||||
|
||||
if( expand_string( 0,
|
||||
nxt_completion,
|
||||
&tmp,
|
||||
ACCEPT_INCOMPLETE |
|
||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
|
||||
path_cpy = wcsdup( path );
|
||||
|
||||
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
|
||||
nxt_path != 0;
|
||||
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
|
||||
{
|
||||
for( i=0; i<al_get_count(&tmp); i++ )
|
||||
nxt_completion = wcsdupcat2( nxt_path,
|
||||
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
|
||||
cmd,
|
||||
(void *)0 );
|
||||
if( ! nxt_completion )
|
||||
continue;
|
||||
|
||||
al_init( &tmp );
|
||||
|
||||
if( expand_string( 0,
|
||||
nxt_completion,
|
||||
&tmp,
|
||||
ACCEPT_INCOMPLETE |
|
||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
al_push( comp, al_get( &tmp, i ) );
|
||||
for( i=0; i<al_get_count(&tmp); i++ )
|
||||
{
|
||||
al_push( comp, al_get( &tmp, i ) );
|
||||
}
|
||||
}
|
||||
|
||||
al_destroy( &tmp );
|
||||
|
||||
}
|
||||
free( path_cpy );
|
||||
|
||||
if( al_get_count( comp ) > prev_count )
|
||||
{
|
||||
complete_cmd_desc( cmd, comp );
|
||||
}
|
||||
|
||||
al_destroy( &tmp );
|
||||
|
||||
}
|
||||
free( path_cpy );
|
||||
|
||||
complete_cmd_desc( cmd, comp );
|
||||
|
||||
|
||||
/*
|
||||
These return the original strings - don't free them
|
||||
*/
|
||||
@@ -1335,7 +1354,6 @@ static void complete_cmd( const wchar_t *cmd,
|
||||
copy_strings_with_prefix( comp, cmd, COMPLETE_BUILTIN_DESC, &builtin_get_desc, &possible_comp );
|
||||
al_destroy( &possible_comp );
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1354,7 +1372,7 @@ static void complete_cmd( const wchar_t *cmd,
|
||||
wcsdupcat2( nxt_path,
|
||||
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
|
||||
cmd,
|
||||
0 );
|
||||
(void *)0 );
|
||||
if( ! nxt_completion )
|
||||
{
|
||||
continue;
|
||||
@@ -1435,29 +1453,29 @@ static void complete_from_args( const wchar_t *str,
|
||||
strings should be escaped!
|
||||
*/
|
||||
/*
|
||||
for( i=0; i< al_get_count( &possible_comp ); i++ )
|
||||
{
|
||||
wchar_t *next = (wchar_t *)al_get( &possible_comp, i );
|
||||
wchar_t *next_unescaped;
|
||||
if( next )
|
||||
{
|
||||
next_unescaped = unescape( next, 0 );
|
||||
if( next_unescaped )
|
||||
{
|
||||
al_set( &possible_comp , i, next_unescaped );
|
||||
}
|
||||
else
|
||||
{
|
||||
al_set( &possible_comp , i, 0 );
|
||||
debug( 2, L"Could not expand string %ls on line %d of file %s", next, __LINE__, __FILE__ );
|
||||
}
|
||||
free( next );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
|
||||
}
|
||||
}
|
||||
for( i=0; i< al_get_count( &possible_comp ); i++ )
|
||||
{
|
||||
wchar_t *next = (wchar_t *)al_get( &possible_comp, i );
|
||||
wchar_t *next_unescaped;
|
||||
if( next )
|
||||
{
|
||||
next_unescaped = unescape( next, 0 );
|
||||
if( next_unescaped )
|
||||
{
|
||||
al_set( &possible_comp , i, next_unescaped );
|
||||
}
|
||||
else
|
||||
{
|
||||
al_set( &possible_comp , i, 0 );
|
||||
debug( 2, L"Could not expand string %ls on line %d of file %s", next, __LINE__, __FILE__ );
|
||||
}
|
||||
free( next );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
copy_strings_with_prefix( comp_out, str, desc, 0, &possible_comp );
|
||||
@@ -1469,7 +1487,7 @@ static void complete_from_args( const wchar_t *str,
|
||||
/**
|
||||
Match against an old style long option
|
||||
*/
|
||||
static int param_match_old( complete_entry_opt *e,
|
||||
static int param_match_old( complete_entry_opt_t *e,
|
||||
wchar_t *optstr )
|
||||
{
|
||||
return (optstr[0] == L'-') && (wcscmp( e->long_opt, &optstr[1] ) == 0);
|
||||
@@ -1478,7 +1496,7 @@ static int param_match_old( complete_entry_opt *e,
|
||||
/**
|
||||
Match a parameter
|
||||
*/
|
||||
static int param_match( complete_entry_opt *e,
|
||||
static int param_match( complete_entry_opt_t *e,
|
||||
wchar_t *optstr )
|
||||
{
|
||||
if( e->short_opt != L'\0' &&
|
||||
@@ -1499,7 +1517,7 @@ static int param_match( complete_entry_opt *e,
|
||||
/**
|
||||
Test if a string is an option with an argument, like --color=auto or -I/usr/include
|
||||
*/
|
||||
static wchar_t *param_match2( complete_entry_opt *e,
|
||||
static wchar_t *param_match2( complete_entry_opt_t *e,
|
||||
wchar_t *optstr )
|
||||
{
|
||||
if( e->short_opt != L'\0' && e->short_opt == optstr[1] )
|
||||
@@ -1571,6 +1589,7 @@ static void complete_load_handler( const wchar_t *cmd )
|
||||
|
||||
void complete_load( const wchar_t *name, int reload )
|
||||
{
|
||||
CHECK( name, );
|
||||
parse_util_load( name,
|
||||
L"fish_complete_path",
|
||||
&complete_load_handler,
|
||||
@@ -1587,8 +1606,8 @@ static int complete_param( wchar_t *cmd_orig,
|
||||
wchar_t *str,
|
||||
array_list_t *comp_out )
|
||||
{
|
||||
complete_entry *i;
|
||||
complete_entry_opt *o;
|
||||
complete_entry_t *i;
|
||||
complete_entry_opt_t *o;
|
||||
|
||||
array_list_t matches;
|
||||
wchar_t *cmd, *path;
|
||||
@@ -1775,7 +1794,7 @@ static void complete_param_expand( wchar_t *str,
|
||||
int do_file )
|
||||
{
|
||||
wchar_t *comp_str;
|
||||
|
||||
|
||||
if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) )
|
||||
{
|
||||
comp_str++;
|
||||
@@ -1784,16 +1803,16 @@ static void complete_param_expand( wchar_t *str,
|
||||
{
|
||||
comp_str = str;
|
||||
}
|
||||
/*
|
||||
debug( 3,
|
||||
L"expand_string( \"%ls\", comp_out, EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | %ls );",
|
||||
comp_str,
|
||||
do_file?L"0":L"EXPAND_SKIP_WILDCARDS" );
|
||||
*/
|
||||
expand_string( 0,
|
||||
wcsdup(comp_str),
|
||||
comp_out,
|
||||
EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS) );
|
||||
|
||||
if( expand_string( 0,
|
||||
wcsdup(comp_str),
|
||||
comp_out,
|
||||
EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS) ) == EXPAND_ERROR )
|
||||
{
|
||||
debug( 3, L"Error while expanding string '%ls'", comp_str );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1820,20 +1839,27 @@ static int complete_variable( const wchar_t *var,
|
||||
|
||||
if( wcsncmp( var, name, varlen) == 0 )
|
||||
{
|
||||
wchar_t *value = expand_escape_variable( env_get( name ));
|
||||
wchar_t *blarg;
|
||||
/*
|
||||
Variable description is 'Variable: VALUE
|
||||
*/
|
||||
blarg = wcsdupcat2( &name[varlen], COMPLETE_SEP_STR, COMPLETE_VAR_DESC_VAL, value, 0 );
|
||||
wchar_t *value_unescaped, *value;
|
||||
|
||||
if( blarg )
|
||||
value_unescaped = env_get( name );
|
||||
if( value_unescaped )
|
||||
{
|
||||
res =1;
|
||||
al_push( comp, blarg );
|
||||
}
|
||||
free( value );
|
||||
wchar_t *desc;
|
||||
|
||||
value = expand_escape_variable( value_unescaped );
|
||||
/*
|
||||
Variable description is 'Variable: VALUE
|
||||
*/
|
||||
desc = wcsdupcat2( &name[varlen], COMPLETE_SEP_STR, COMPLETE_VAR_DESC_VAL, value, (void *)0 );
|
||||
|
||||
if( desc )
|
||||
{
|
||||
res =1;
|
||||
al_push( comp, desc );
|
||||
}
|
||||
free( value );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1953,7 +1979,7 @@ static int try_complete_user( const wchar_t *cmd,
|
||||
L"/",
|
||||
COMPLETE_SEP_STR,
|
||||
COMPLETE_USER_DESC,
|
||||
0 );
|
||||
(void *)0 );
|
||||
if( blarg != 0 )
|
||||
{
|
||||
al_push( comp, blarg );
|
||||
@@ -2130,6 +2156,14 @@ void complete( const wchar_t *cmd,
|
||||
int do_file;
|
||||
|
||||
do_file = complete_param( current_command, prev_token, current_token, comp );
|
||||
|
||||
/*
|
||||
If we have found no command specific completions at
|
||||
all, fall back to using file completions.
|
||||
*/
|
||||
if( !al_get_count( comp ) )
|
||||
do_file = 1;
|
||||
|
||||
complete_param_expand( current_token, comp, do_file );
|
||||
}
|
||||
}
|
||||
@@ -2165,11 +2199,13 @@ static void append_switch( string_buffer_t *out,
|
||||
|
||||
void complete_print( string_buffer_t *out )
|
||||
{
|
||||
complete_entry *e;
|
||||
complete_entry_t *e;
|
||||
|
||||
CHECK( out, );
|
||||
|
||||
for( e = first_entry; e; e=e->next )
|
||||
{
|
||||
complete_entry_opt *o;
|
||||
complete_entry_opt_t *o;
|
||||
for( o= e->first_option; o; o=o->next )
|
||||
{
|
||||
wchar_t *modestr[] =
|
||||
|
||||
562
configure.ac
562
configure.ac
@@ -1,7 +1,25 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(fish,1.21.11,fish-users@lists.sf.net)
|
||||
|
||||
#
|
||||
# This file is the main build configuration file for fish. It is used
|
||||
# to determine your systems capabilities, and tries to adapt fish to
|
||||
# take maximum advantage of the services your system offers.
|
||||
#
|
||||
# Process this file using the 'autoconf' command to produce a working
|
||||
# configure script, which should in turn be executed in order to
|
||||
# configure the build process.
|
||||
#
|
||||
|
||||
AC_INIT(fish,1.22.0,fish-users@lists.sf.net)
|
||||
|
||||
|
||||
#
|
||||
# If needed, run autoconf to regenerate the configure file
|
||||
#
|
||||
# This makes sure that after running autoconf once to create the first
|
||||
# version of configure, we never again need to worry about manually
|
||||
# running autoconf to handle an updates configure.ac.
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if autoconf needs to be run])
|
||||
if test configure -ot configure.ac; then
|
||||
AC_MSG_RESULT([yes])
|
||||
@@ -11,38 +29,55 @@ if test configure -ot configure.ac; then
|
||||
AC_MSG_NOTICE([running autoconf])
|
||||
if autoconf; then
|
||||
./configure "$@"
|
||||
exit
|
||||
fi
|
||||
exit
|
||||
exit 1
|
||||
else
|
||||
AC_MSG_ERROR( [cannot find the autoconf program in your path.
|
||||
AC_MSG_ERROR(
|
||||
[cannot find the autoconf program in your path.
|
||||
This program needs to be run whenever the configure.ac file is modified.
|
||||
Please install it and try again.])
|
||||
Please install it and try again.]
|
||||
)
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# If needed, run autoheader to regenerate config.h.in
|
||||
#
|
||||
# This makes sure we never ever have to run autoheader manually. It
|
||||
# will be run whenever needed automatically.
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if autoheader needs to be run])
|
||||
if test ! -f ./config.h.in -o config.h.in -ot configure.ac; then
|
||||
AC_MSG_RESULT([yes])
|
||||
if which autoheader >/dev/null; then
|
||||
AC_MSG_NOTICE([running autoheader])
|
||||
autoheader
|
||||
autoheader || exit 1
|
||||
else
|
||||
AC_MSG_ERROR( [cannot find the autoheader program in your path.
|
||||
AC_MSG_ERROR(
|
||||
[cannot find the autoheader program in your path.
|
||||
This program needs to be run whenever the configure.ac file is modified.
|
||||
Please install it and try again.])
|
||||
Please install it and try again.]
|
||||
)
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Detect directories which may contain additional headers, libraries
|
||||
# and commands. This needs to be done early - before Autoconf starts
|
||||
# to mess with CFLAGS and all the other environemnt variables.
|
||||
#
|
||||
# This mostly helps OS X users, since fink usually installs out of
|
||||
# tree and doesn't update CFLAGS.
|
||||
#
|
||||
|
||||
for i in /usr/pkg /sw /opt /opt/local; do
|
||||
|
||||
AC_MSG_CHECKING([for $i/include include directory])
|
||||
@@ -74,24 +109,57 @@ done
|
||||
|
||||
AC_SUBST( optbindirs, $optbindirs )
|
||||
|
||||
|
||||
#
|
||||
# Tell autoconf to create config.h header
|
||||
#
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
|
||||
#
|
||||
# This adds markup to the code that results in a few extra compile
|
||||
# time checks on recent GCC versions. It helps stop a few common bugs.
|
||||
#
|
||||
|
||||
AH_BOTTOM([#if __GNUC__ >= 3
|
||||
#define __warn_unused __attribute__ ((warn_unused_result))
|
||||
#define __sentinel __attribute__ ((sentinel))
|
||||
#else
|
||||
#define __warn_unused
|
||||
#define __sentinel
|
||||
#endif])
|
||||
|
||||
|
||||
#
|
||||
# Set up various programs needed for install
|
||||
#
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
|
||||
|
||||
#
|
||||
# Check for seq command. If missing, make sure fallback shellscript
|
||||
# implementation is installed
|
||||
# implementation is installed.
|
||||
#
|
||||
|
||||
AC_CHECK_PROG( SEQ_FALLBACK, seq, [ ], [seq])
|
||||
|
||||
|
||||
#
|
||||
# Optionally drop xsel command
|
||||
AC_ARG_WITH( xsel,
|
||||
AC_HELP_STRING([--without-xsel],
|
||||
[do not build the xsel program needed for X clipboard integration]),
|
||||
[xsel=$withval],
|
||||
[xsel=with_xsel] )
|
||||
#
|
||||
|
||||
AC_ARG_WITH(
|
||||
xsel,
|
||||
AC_HELP_STRING(
|
||||
[--without-xsel],
|
||||
[do not build the xsel program needed for X clipboard integration]
|
||||
),
|
||||
[xsel=$withval],
|
||||
[xsel=with_xsel]
|
||||
)
|
||||
|
||||
if [[ "$xsel" = "with_xsel" ]]; then
|
||||
AC_SUBST( XSEL,[xsel-0.9.6/xsel])
|
||||
@@ -103,38 +171,46 @@ else
|
||||
AC_SUBST( XSEL_MAN_PATH,[ ])
|
||||
fi
|
||||
|
||||
# These help out with getting better prototypes on some platforms
|
||||
|
||||
#
|
||||
# Test if the compiler accepts the -std=c99 flag. If so, using it
|
||||
# increases the odds of correct compilation, since we want to use the
|
||||
# *wprintf functions, which where defined in C99. On some platforms
|
||||
# (Solaris 10) adding -std=c99 in turn requires that _POSIX_C_SOURCE
|
||||
# be defined to 200112L otherwise several POSIX-specific, non-ISO-C99
|
||||
# types/prototypes are made unavailable e.g. siginfo_t. Finally,
|
||||
# defining _XOPEN_SOURCE to 600 is compatible with the
|
||||
# _POSIX_C_SOURCE value and provides a little assurance that
|
||||
# extension functions' prototypes are available, e.g. killpg().
|
||||
# *wprintf functions, which where defined in C99.
|
||||
#
|
||||
|
||||
XCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -std=c99 -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L"
|
||||
AC_MSG_CHECKING(if -std=c99 -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L works)
|
||||
AC_CACHE_VAL(local_cv_has__std_c99,[
|
||||
AC_TRY_RUN([
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
CFLAGS="$CFLAGS -std=c99"
|
||||
XCPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS -std=c99"
|
||||
AC_MSG_CHECKING(if -std=c99 works)
|
||||
|
||||
AC_CACHE_VAL(
|
||||
local_cv_has__std_c99,
|
||||
[
|
||||
AC_TRY_RUN(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
],
|
||||
local_cv_has__std_c99=yes,
|
||||
local_cv_has__std_c99=no,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}],
|
||||
local_cv_has__std_c99=yes,
|
||||
local_cv_has__std_c99=no,
|
||||
)])
|
||||
AC_MSG_RESULT($local_cv_has__std_c99)
|
||||
case x$local_cv_has__std_c99 in
|
||||
xno) CFLAGS="$XCFLAGS" ;;
|
||||
xno)
|
||||
CFLAGS="$XCFLAGS"
|
||||
CPPFLAGS="$XCPPFLAGS" ;;
|
||||
esac
|
||||
|
||||
|
||||
#
|
||||
# If we are using gcc, set some flags that increase the odds of the
|
||||
# compiler producing a working binary...
|
||||
@@ -144,7 +220,7 @@ if test "$CC" = gcc; then
|
||||
|
||||
#
|
||||
# -fno-optimize-sibling-calls seems to work around a bug where
|
||||
# sending a SIGWINCH to fish on NetBSD causes fish to exit when
|
||||
# sending a SIGWINCH to fish on NetBSD 3.0 causes fish to exit when
|
||||
# compiled with GCC 3.3.3. This is probably either a compiler bug
|
||||
# or a libc bug, but adding this flag seems to fix things for
|
||||
# now. Long term, the real problem should be tracked down and
|
||||
@@ -163,6 +239,7 @@ if test "$CC" = gcc; then
|
||||
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# If we are compiling against glibc, set some flags to work around
|
||||
# some rather stupid attempts to hide prototypes for *wprintf
|
||||
@@ -171,16 +248,24 @@ fi
|
||||
|
||||
AC_MSG_CHECKING([if we are compiling against glibc])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#include <stdlib.h>
|
||||
#ifdef __GLIBC__
|
||||
#define STATUS 0
|
||||
#else
|
||||
#define STATUS 1
|
||||
#endif],
|
||||
[return STATUS;])],
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#ifdef __GLIBC__
|
||||
#define STATUS 0
|
||||
#else
|
||||
#define STATUS 1
|
||||
#endif
|
||||
],
|
||||
[
|
||||
return STATUS;
|
||||
]
|
||||
)
|
||||
],
|
||||
[glibc=yes],
|
||||
[glibc=no] )
|
||||
[glibc=no]
|
||||
)
|
||||
|
||||
if test "$glibc" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
@@ -192,12 +277,13 @@ if test "$glibc" = yes; then
|
||||
# fallback.h, in order to keep fish working on non-gnu platforms.
|
||||
#
|
||||
|
||||
AC_DEFINE( _GNU_SOURCE, 1, [Macro to enable additional prototypes under Glibc])
|
||||
AC_DEFINE( _ISOC99_SOURCE, 1, [Macro to enable additional prototypes under Glibc])
|
||||
CFLAGS="$CFLAGS -D_GNU_SOURCE=1 -D_ISO99_SOURCE=1"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Test cpu for special handling of ppc
|
||||
#
|
||||
# This is used to skip use of tputs on ppc systems, since it seemed to
|
||||
@@ -207,13 +293,18 @@ fi
|
||||
# hardware available to narrow this problem down, and in practice, it
|
||||
# seems that tputs is never really needed.
|
||||
#
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
if test $target_cpu = powerpc; then
|
||||
AC_DEFINE([TPUTS_KLUDGE],[1],[Evil kludge to get Power based machines to work])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Solaris-specific flags go here
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if we are under Solaris])
|
||||
case $target_os in
|
||||
solaris*)
|
||||
@@ -226,7 +317,10 @@ case $target_os in
|
||||
esac
|
||||
|
||||
|
||||
#
|
||||
# BSD-specific flags go here
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if we are under BSD])
|
||||
case $target_os in
|
||||
*bsd*)
|
||||
@@ -240,10 +334,13 @@ case $target_os in
|
||||
esac
|
||||
|
||||
|
||||
#
|
||||
# Set up PREFIX and related preprocessor symbols. Fish needs to know
|
||||
# where it will be installed. One of the reasons for this is so that
|
||||
# it can make sure the fish installation directory is in the path
|
||||
# during startup.
|
||||
#
|
||||
|
||||
if [[ "$prefix" = NONE ]]; then
|
||||
export prefix=/usr/local
|
||||
AC_SUBST( prefix, /usr/local)
|
||||
@@ -252,129 +349,386 @@ else
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Set up the directory where the documentation files should be
|
||||
# installed
|
||||
#
|
||||
|
||||
AC_ARG_VAR( [docdir], [Documentation direcotry] )
|
||||
|
||||
if test -z $docdir; then
|
||||
AC_SUBST(docdir, [$datadir/doc/fish] )
|
||||
AC_SUBST(docdir, [$datadir/doc/fish] )
|
||||
else
|
||||
AC_SUBST(docdir, [$docdir])
|
||||
AC_SUBST(docdir, [$docdir])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Set up locale directory. This is where the .po files will be
|
||||
# installed.
|
||||
#
|
||||
|
||||
AC_SUBST( [localedir], [$datadir/locale])
|
||||
|
||||
|
||||
#
|
||||
# See if Linux procfs is present. This is used to get extra
|
||||
# information about running processes.
|
||||
#
|
||||
|
||||
AC_CHECK_FILES([/proc/self/stat])
|
||||
|
||||
|
||||
#
|
||||
# This is ued to tell the wgetopt library to translate strings. This
|
||||
# way wgetopt can be dropped into any project without requiring i18n.
|
||||
#
|
||||
|
||||
AC_DEFINE([HAVE_TRANSLATE_H], [1],
|
||||
[Define to 1 if the wgettext function should be used for translating strings.])
|
||||
AC_DEFINE(
|
||||
[HAVE_TRANSLATE_H],
|
||||
[1],
|
||||
[Define to 1 if the wgettext function should be used for translating strings.]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Check presense of various libraries
|
||||
#
|
||||
|
||||
# Check for presense of various libraries
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
AC_SEARCH_LIBS( connect, socket, , [AC_MSG_ERROR([Cannot find the socket library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( nanosleep, rt, , [AC_MSG_ERROR([Cannot find the rt library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( setupterm, [ncurses curses], , [AC_MSG_ERROR([Could not find a curses implementation, needed to build fish])] )
|
||||
|
||||
# Check for presense of various header files
|
||||
|
||||
#
|
||||
# Check presense of various header files
|
||||
#
|
||||
|
||||
AC_CHECK_HEADERS([getopt.h termio.h sys/resource.h term.h ncurses/term.h libintl.h ncurses.h curses.h stropts.h siginfo.h sys/select.h sys/ioctl.h sys/termios.h])
|
||||
|
||||
AC_CHECK_HEADER([regex.h],
|
||||
[AC_DEFINE([HAVE_REGEX_H], [1], [Define to 1 if you have the <regex.h> header file.])],
|
||||
[AC_MSG_ERROR([Could not find the header regex.h, needed to build fish])])
|
||||
AC_CHECK_HEADER(
|
||||
[regex.h],
|
||||
[
|
||||
AC_DEFINE(
|
||||
[HAVE_REGEX_H],
|
||||
[1],
|
||||
[Define to 1 if you have the <regex.h> header file.]
|
||||
)],
|
||||
[AC_MSG_ERROR([Could not find the header regex.h, needed to build fish])
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# On some platforms (Solaris 10) adding -std=c99 in turn requires that
|
||||
# _POSIX_C_SOURCE be defined to 200112L otherwise several
|
||||
# POSIX-specific, non-ISO-C99 types/prototypes are made unavailable
|
||||
# e.g. siginfo_t. Defining _XOPEN_SOURCE to 600 is compatible with
|
||||
# the _POSIX_C_SOURCE value and provides a little assurance that
|
||||
# extension functions' prototypes are available, e.g. killpg().
|
||||
#
|
||||
# Some other platforms (OS X), will remove types/prototypes/macros
|
||||
# e.g. SIGWINCH if either _POSIX_C_SOURCE or _XOPEN_SOURCE is defined.
|
||||
#
|
||||
# This test adds these macros only if they enable a program that uses
|
||||
# both Posix and non-standard features to compile, and that program
|
||||
# does not compile without these macros.
|
||||
#
|
||||
# We try to make everyone happy.
|
||||
#
|
||||
# The ordering of the various autoconf tests is very critical as well:
|
||||
#
|
||||
# * This test needs to be run _after_ header detection tests, so that
|
||||
# the proper headers are included.
|
||||
#
|
||||
# * This test needs to be run _before_ testing for the presense of any
|
||||
# prototypes or other language functinality.
|
||||
#
|
||||
# * This test should be (but does not need to be) run after the
|
||||
# conditional definition of __EXTENSIONS__, to avoid redundant tests.
|
||||
#
|
||||
|
||||
XCFLAGS="$CFLAGS"
|
||||
|
||||
echo Checking how to use -D_XOPEN_SOURCE=600 and -D_POSIX_C_SOURCE=200112L...
|
||||
local_found_posix_switch=no
|
||||
|
||||
for i in "" "-D_POSIX_C_SOURCE=200112L" "-D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L"; do
|
||||
|
||||
AC_MSG_CHECKING( if switches \"$i\" works)
|
||||
CFLAGS="$XCFLAGS $i"
|
||||
|
||||
#
|
||||
# Try to run this program, which should test various extensions
|
||||
# and Posix functionality. If this program works, then everything
|
||||
# should work. Hopefully.
|
||||
#
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* POSIX, C89 and C99: POSIX extends this header.
|
||||
* For: kill(), killpg(), siginfo_t, sigset_t,
|
||||
* struct sigaction, sigemptyset(), sigaction(),
|
||||
* SIGIO and SIGWINCH. */
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SIGINFO_H
|
||||
/* Neither POSIX, C89 nor C99: Solaris-specific (others?).
|
||||
* For: siginfo_t (also defined by signal.h when in
|
||||
* POSIX/extensions mode). */
|
||||
#include <siginfo.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TERMIOS_H
|
||||
/* Neither POSIX, C89 nor C99: a common extension.
|
||||
* For: TIOCGWINSZ and struct winsize (under at least
|
||||
* Solaris, NetBSD and (dual-listed) FreeBSD). */
|
||||
#include <sys/termios.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* As above (under at least Linux and FreeBSD). */
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
/* Avert high-level optimisation, by making the program's
|
||||
* return value depend on all tested identifiers. */
|
||||
int ret = 0;
|
||||
/* POSIX only: might be unhidden by _POSIX_C_SOURCE. */
|
||||
struct sigaction sa;
|
||||
sigset_t ss;
|
||||
siginfo_t info;
|
||||
ret += (int)(void *)&info + kill( 0, 0 ) +
|
||||
sigaction( 0, &sa, 0 ) + sigemptyset( &ss );
|
||||
/* Extended-POSIX: might be unhidden by _XOPEN_SOURCE. */
|
||||
ret += killpg( 0, 0 );
|
||||
/* Non-standard: might be hidden by the macros. */
|
||||
{
|
||||
struct winsize termsize;
|
||||
ret += (int)(void *)&termsize;
|
||||
ret += SIGWINCH + TIOCGWINSZ + SIGIO;
|
||||
}
|
||||
return ret;
|
||||
|
||||
],
|
||||
local_cv_use__posix_c_source=yes,
|
||||
local_cv_use__posix_c_source=no,
|
||||
)
|
||||
|
||||
if test x$local_cv_use__posix_c_source = xyes; then
|
||||
AC_MSG_RESULT( yes )
|
||||
local_found_posix_switch=yes
|
||||
break;
|
||||
else
|
||||
AC_MSG_RESULT( no )
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
#
|
||||
# We didn't find any combination of switches that worked - revert to
|
||||
# no switches and hope that the fallbacks work. A warning will be
|
||||
# printed at the end of the configure script.
|
||||
#
|
||||
|
||||
if test ! x$local_found_posix_switch = xyes; then
|
||||
CFLAGS="$XCFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Check for presense of various functions used by fish
|
||||
#
|
||||
|
||||
# Check for presense of various functions
|
||||
AC_CHECK_FUNCS( gettext wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
|
||||
AC_CHECK_FUNCS( futimes wcwidth wcswidth getopt_long wcstok fputwc fgetwc )
|
||||
AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
|
||||
AC_CHECK_FUNCS( wcstol dcgettext wcslcat wcslcpy lrand48_r killpg)
|
||||
|
||||
# The Makefile also needs to know if we have gettext, so it knows if the translations should be installed.
|
||||
|
||||
#
|
||||
# The Makefile also needs to know if we have gettext, so it knows if
|
||||
# the translations should be installed.
|
||||
#
|
||||
|
||||
AC_CHECK_FUNC( gettext, AC_SUBST( HAVE_GETTEXT, 1 ), AC_SUBST( HAVE_GETTEXT, 0 ) )
|
||||
|
||||
#
|
||||
# Here follows a list of small programs used to test for various
|
||||
# features that Autoconf doesn't tell us about
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Check if realpath accepts null for its second argument
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if realpath accepts null for its second argument])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>],
|
||||
[int status; char *res; res = realpath( "somefile", 0 ); status = !(res != 0 || errno == ENOENT); exit( status );])],
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
],
|
||||
[
|
||||
int status;
|
||||
char *res;
|
||||
res = realpath( "somefile", 0 );
|
||||
status = !(res != 0 || errno == ENOENT);
|
||||
exit( status );
|
||||
]
|
||||
)
|
||||
],
|
||||
[have_realpath_null=yes],
|
||||
[have_realpath_null=no] )
|
||||
[have_realpath_null=no]
|
||||
)
|
||||
|
||||
if test "$have_realpath_null" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_REALPATH_NULL], [1],
|
||||
[Define to 1 if realpath accepts null for its second argument.])
|
||||
AC_DEFINE(
|
||||
[HAVE_REALPATH_NULL],
|
||||
[1],
|
||||
[Define to 1 if realpath accepts null for its second argument.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
|
||||
# Check if struct winsize exists
|
||||
#
|
||||
# Check if struct winsize and TIOCGWINSZ exist
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if struct winsize and TIOCGWINSZ exist])
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#ifdef HAVE_SYS_TERMIOS_H
|
||||
#include <sys/termios.h>
|
||||
#endif
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#ifdef HAVE_SYS_TERMIOS_H
|
||||
#include <sys/termios.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
struct winsize termsize = {0};
|
||||
TIOCGWINSZ;
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(yes);
|
||||
AC_DEFINE([HAVE_WINSIZE], [1], [Define to 1 if the winsize struct and TIOCGWINSZ macro exist])
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
]
|
||||
)
|
||||
|
||||
],
|
||||
[struct winsize termsize = {0}; TIOCGWINSZ;])],
|
||||
[AC_MSG_RESULT(yes); AC_DEFINE([HAVE_WINSIZE], [1], [Define to 1 if the winsize struct and TIOCGWINSZ macro exist])],
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
#
|
||||
# If we have a fwprintf in libc, test that it actually works. As of
|
||||
# March 2006, it is broken under Dragonfly BSD.
|
||||
#
|
||||
|
||||
if test "$ac_cv_func_fwprintf" = yes; then
|
||||
|
||||
AC_MSG_CHECKING([if fwprintf is broken])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
],
|
||||
[
|
||||
setlocale( LC_ALL, "" );
|
||||
fwprintf( stderr, L"%ls%ls", L"", L"fish:" );
|
||||
])],
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
],
|
||||
[
|
||||
setlocale( LC_ALL, "" );
|
||||
fwprintf( stderr, L"%ls%ls", L"", L"fish:" );
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_BROKEN_FWPRINTF], [1], [Define to 1 one if the implemented fwprintf is broken])
|
||||
] )
|
||||
]
|
||||
)
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check for _nl_msg_cat_cntr symbol
|
||||
AC_MSG_CHECKING([for _nl_msg_cat_cntr symbol])
|
||||
AC_TRY_LINK([#if HAVE_LIBINTL_H]
|
||||
[#include <libintl.h>]
|
||||
[#endif],
|
||||
[extern int _nl_msg_cat_cntr;]
|
||||
[int tmp = _nl_msg_cat_cntr; exit(tmp);], have__nl_msg_cat_cntr=yes, have__nl_msg_cat_cntr=no)
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#if HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
extern int _nl_msg_cat_cntr;
|
||||
int tmp = _nl_msg_cat_cntr;
|
||||
exit(tmp);
|
||||
],
|
||||
have__nl_msg_cat_cntr=yes,
|
||||
have__nl_msg_cat_cntr=no
|
||||
)
|
||||
if test "$have__nl_msg_cat_cntr" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE__NL_MSG_CAT_CNTR], [1],
|
||||
[Define to 1 if the _nl_msg_cat_cntr symbol is exported.])
|
||||
AC_DEFINE(
|
||||
[HAVE__NL_MSG_CAT_CNTR],
|
||||
[1],
|
||||
[Define to 1 if the _nl_msg_cat_cntr symbol is exported.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check if getopt_long exists and works
|
||||
AC_MSG_CHECKING([if getopt_long exists and works])
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#if HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
static struct option
|
||||
long_options[] =
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
;
|
||||
int opt = getopt_long( 0,
|
||||
0,
|
||||
0,
|
||||
long_options,
|
||||
0 );
|
||||
|
||||
],
|
||||
have_working_getopt_long=yes,
|
||||
have_working_getopt_long=no
|
||||
)
|
||||
if test "$have_working_getopt_long" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(
|
||||
[HAVE_WORKING_GETOPT_LONG],
|
||||
[1],
|
||||
[Define to 1 if getopt_long exists and works.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
@@ -386,7 +740,11 @@ AC_MSG_CHECKING([If del_curterm is broken])
|
||||
case $target_os in
|
||||
*bsd*)
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_BROKEN_DEL_CURTERM],[1],[del_curterm si broken, redefine it to a no-op to avoid a double-free bug])
|
||||
AC_DEFINE(
|
||||
[HAVE_BROKEN_DEL_CURTERM],
|
||||
[1],
|
||||
[del_curterm is broken, redefine it to a no-op to avoid a double-free bug]
|
||||
)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -394,8 +752,14 @@ case $target_os in
|
||||
esac
|
||||
|
||||
# Tell the world what we know
|
||||
AC_CONFIG_FILES([Makefile fish.spec doc_src/fish.1 doc_src/Doxyfile seq])
|
||||
AC_CONFIG_FILES([Makefile fish.spec doc_src/Doxyfile seq])
|
||||
AC_OUTPUT
|
||||
|
||||
if test ! x$local_found_posix_switch = xyes; then
|
||||
echo "Can't find a combination of switches to enable common extensions like detecting window size."
|
||||
echo "Some fish features may be disabled."
|
||||
fi
|
||||
|
||||
echo "fish is now configured."
|
||||
echo "Use 'make' and 'make install' to build and install fish."
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section and and - Conditionally execute a command
|
||||
\section and and - conditionally execute a command
|
||||
|
||||
\subsection and-synopsis Synopsis
|
||||
<tt>COMMAND1; and COMMAND2</tt>
|
||||
@@ -7,7 +6,7 @@
|
||||
\subsection and-description Description
|
||||
|
||||
The \c and builtin is used to execute a command if the current exit
|
||||
status (as set by the last previous command) is zero
|
||||
status (as set by the last previous command) is 0.
|
||||
|
||||
The and command does not change the current exit status.
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
\section begin begin - Start a new block of code
|
||||
\section begin begin - start a new block of code
|
||||
|
||||
\subsection begin-synopsis Synopsis
|
||||
<tt>begin; [COMMAND;...] end </tt>
|
||||
<tt>begin; [COMMANDS...;] end</tt>
|
||||
|
||||
\subsection begin-description Description
|
||||
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
\section bind bind - Handle key bindings.
|
||||
\section bind bind - handle key bindings
|
||||
|
||||
\subsection bind-synopsis Synopsis
|
||||
<tt>bind [OPTIONS] [BINDINGS...] </tt>
|
||||
<tt>bind [OPTIONS] [BINDINGS...]</tt>
|
||||
|
||||
The <tt>bind</tt> builtin causes fish to add the readline style bindings specified by <tt>BINDINGS</tt> to the list of key bindings. For more information on specifying keyboard bindings, use <tt>man readline</tt> to access the readline documentation.
|
||||
The <tt>bind</tt> builtin causes fish to add the readline style bindings specified by BINDINGS to the list of key bindings, as if they appeared in your <tt>~/.fish_inputrc</tt> file.
|
||||
|
||||
For more information on the syntax keyboard bindings, use <tt>man
|
||||
readline</tt> to access the readline documentation. The availiable commands
|
||||
are listed in the <a href="index.html#editor">Command Line Editor</a> section
|
||||
of the fish manual - but you may also use any fish command! To write such
|
||||
commands, see the <a href="#commandline">commandline</a> builtin. It's good
|
||||
practice to put the code into a <tt><a href="#function">function</a> -b</tt>
|
||||
and bind to the function name.
|
||||
|
||||
\subsection bind-description Description
|
||||
- <tt>-M MODE</tt> or <tt>--set-mode=MODE</tt> sets the current input mode to MODE.
|
||||
|
||||
|
||||
\subsection bind-example Example
|
||||
|
||||
<tt>bind -M vi</tt> changes to the vi input mode
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section block block - Temporarily block delivery of events
|
||||
\section block block - temporarily block delivery of events
|
||||
|
||||
\subsection block-synopsis Synopsis
|
||||
<tt>block [OPTIONS...]</tt>
|
||||
@@ -12,7 +11,8 @@
|
||||
|
||||
\subsection block-example Example
|
||||
|
||||
<pre>block -g
|
||||
<pre>
|
||||
block -g
|
||||
\#Do something that should not be interrupted
|
||||
block -e
|
||||
</pre>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
\section break break - stop the innermost currently evaluated loop
|
||||
|
||||
\subsection break-synopsis Synopsis
|
||||
@@ -9,13 +8,12 @@ The \c break builtin is used to halt a currently running loop, such as a <a href
|
||||
|
||||
\subsection break-example Example
|
||||
The following code searches all .c files for smurfs, and halts at the first occurrence.
|
||||
<p>
|
||||
<tt>for i in *.c;
|
||||
<br> if grep smurf $i;
|
||||
<br> echo Smurfs are present in $i;
|
||||
<br> break;
|
||||
<br> end;
|
||||
<br>end;
|
||||
</tt>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for i in *.c
|
||||
if grep smurf $i
|
||||
echo Smurfs are present in $i
|
||||
break
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
\section builtin builtin - run a builtin command
|
||||
|
||||
\subsection builtin-synopsis Synopsis
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
\section case case - conditionally execute a block of commands
|
||||
|
||||
\subsection case-synopsis Synopsis
|
||||
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end</tt>
|
||||
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end</tt>
|
||||
|
||||
\subsection case-description Description
|
||||
|
||||
@@ -32,7 +32,6 @@ forms of parameter expansion have been performed for the case command.
|
||||
If the variable \$animal contains the name of an animal, the following
|
||||
code would attempt to classify it:
|
||||
|
||||
<p>
|
||||
<pre>
|
||||
switch $animal
|
||||
case cat
|
||||
@@ -47,7 +46,7 @@ switch $animal
|
||||
echo I have no idea what a $animal is
|
||||
end
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
If the above code was run with \c \$animal set to \c whale, the output would be \c mammal.
|
||||
</p>
|
||||
|
||||
If the above code was run with \c \$animal set to \c whale, the output
|
||||
would be \c mammal.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section commandline commandline - Set or get the current commandline buffer
|
||||
\section commandline commandline - set or get the current commandline buffer
|
||||
|
||||
\subsection commandline-synopsis Synopsis
|
||||
<tt>commandline [OPTIONS] [CMD]</tt>
|
||||
@@ -9,8 +9,22 @@
|
||||
- \c CMD is the new value of the commandline. If unspecified, the
|
||||
current value of the commandline is written to standard output.
|
||||
|
||||
The following switches change what the commandline builtin does
|
||||
|
||||
- \c -C or \c --cursor set or get the current cursor position, not
|
||||
the contents of the buffer. If no argument is given, the current
|
||||
cursor position is printed, otherwise the argument is interpreted
|
||||
as the new cursor position.
|
||||
- \c -f or \c --function inject readline functions into the
|
||||
reader. This option can not be combined with any other option. It
|
||||
will cause any additional arguments to be interpreted as readline
|
||||
functions, and these functions will be injected into the reader, so
|
||||
that they will be returned to the reader before any additional
|
||||
actual keypresses are read.
|
||||
|
||||
|
||||
The following switches change the way \c commandline updates the
|
||||
commandline
|
||||
commandline buffer
|
||||
|
||||
- \c -a or \c --append do not remove the current commandline, append
|
||||
the specified string at the end of it
|
||||
@@ -28,20 +42,12 @@ or updated
|
||||
- \c -t or \c --current_token select the current token.
|
||||
|
||||
The following switch changes the way \c commandline prints the current
|
||||
commandline
|
||||
commandline buffer
|
||||
|
||||
- \c -c or \c --cut-at-cursor only print selection up until the
|
||||
current cursor position
|
||||
- \c -o or \c --tokenize tokenize the selection and print one string-type token per line
|
||||
|
||||
Other switches
|
||||
|
||||
- \c -f or \c --function inject readline functions into the
|
||||
reader. This option can not be combined with any other option. It
|
||||
will cause any additional arguments to be interpreted as readline
|
||||
functions, and these functions will be injected into the reader, so
|
||||
that they will be returned to the reader before any additional
|
||||
actual keypresses are read.
|
||||
|
||||
If commandline is called during a call to complete a given string
|
||||
using <code>complete -C STRING</code>, commandline will consider the
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section contains contains - Test if a word is present in a list
|
||||
\section contains contains - test if a word is present in a list
|
||||
|
||||
\subsection contains-synopsis Synopsis
|
||||
<code>contains [OPTIONS] KEY [VALUES...]</code>
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
|
||||
\section continue continue - skip the rest of the current lap of the innermost currently evaluated loop
|
||||
|
||||
\subsection continue-synopsis Synopsis
|
||||
<tt>LOOP_CONSTRUCT; [COMMANDS...] continue; [COMMANDS...] end</tt>
|
||||
<tt>LOOP_CONSTRUCT; [COMMANDS...;] continue; [COMMANDS...;] end</tt>
|
||||
|
||||
\subsection continue-description Description
|
||||
The \c continue builtin is used to skip the current lap of the innermost currently running loop, such as a <a href="#for">for</a> loop or a <a href="#while">while</a> loop. It is usually added inside of a conditional block such as an <a href="#if">if</a> statement or a <a href="#switch">switch</a> statement.
|
||||
|
||||
\subsection continue-example Example
|
||||
The following code removes all tmp files without smurfs.
|
||||
<p>
|
||||
<tt>for i in *.tmp;
|
||||
<br> if grep smurf $i;
|
||||
<br> continue;
|
||||
<br> end;
|
||||
<br> rm $i;
|
||||
<br>end;
|
||||
</tt>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for i in *.tmp
|
||||
if grep smurf $i
|
||||
continue
|
||||
end
|
||||
rm $i
|
||||
end
|
||||
</pre>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section count count - Count the number of elements of an array
|
||||
\section count count - count the number of elements of an array
|
||||
|
||||
\subsection count-synopsis Synopsis
|
||||
<tt>count $VARIABLE</tt>
|
||||
|
||||
155
doc_src/design.hdr
Normal file
155
doc_src/design.hdr
Normal file
@@ -0,0 +1,155 @@
|
||||
/** \page design Design document
|
||||
|
||||
\section design-overview Overview
|
||||
|
||||
This is a description of the design principles that have been used to
|
||||
design fish. The fish design has three high level goals. These are:
|
||||
|
||||
-# Everything that can be done in other shell languages should be
|
||||
possible to do in fish, though fish may rely on external commands in
|
||||
doing so.
|
||||
-# Fish should be user friendly, but not at the expense of expressiveness.
|
||||
Most tradeoffs between power and ease of use can be avoided with careful design.
|
||||
-# Whenever possible without breaking the above goals, fish should
|
||||
follow the Posix syntax.
|
||||
|
||||
To achive these high-level goals, the fish design relies on a number
|
||||
of more specific design principles. These are presented below,
|
||||
together with a rationale and a few examples for each.
|
||||
|
||||
\section ortho The law of orthogonality
|
||||
|
||||
The shell language should have a small set of orthogonal features. Any
|
||||
situation where two features are related but not identical, one of them
|
||||
should be removed, and the other should be made powerful and general
|
||||
enough to handle all common use cases of either feature.
|
||||
|
||||
Rationale:
|
||||
|
||||
Related features make the language larger, which makes it harder to
|
||||
learn. It also increases the size of the sourcecode, making the
|
||||
program harder to maintain and update.
|
||||
|
||||
Examples:
|
||||
|
||||
- Here documents are too similar to using echo inside of a pipeline.
|
||||
- Subshells, command substitution and process substitution are strongly related. \c fish only supports command substitution, the others can be achived either using a block or the psub shellscript function.
|
||||
- Having both aliases and functions is confusing, especially since both of them have limitations and problems. \c fish functions have none of the drawbacks of either syntax.
|
||||
- The many Posix quoting styles are silly, especially \$''.
|
||||
|
||||
|
||||
\section sep The law of minimalism
|
||||
|
||||
The shell should only contain features that cannot be implemented in
|
||||
a reasonable way outside of the shell. A large performance decrease,
|
||||
as well as some program complexity increase is acceptable in order to
|
||||
improve separation.
|
||||
|
||||
Rationale:
|
||||
|
||||
A modular project is easier to maintain since smaller programs are far
|
||||
easier to understand than larger ones. A modular project is also more
|
||||
future proof since the modules can be individually
|
||||
replaced. Modularity also decreases the severity of bugs, since there
|
||||
is good hope that a bug, even a serious one, in one module, does not
|
||||
take the whole system down.
|
||||
|
||||
Examples:
|
||||
|
||||
- Builtin commands should only be created when it cannot be
|
||||
avoided. \c echo, \c kill, \c printf and \c time are among the commands
|
||||
that fish does not implement internally since they can be provided as
|
||||
external commands. Several other commands that are commonly implemented
|
||||
as builtins and can not be implemented as external commands,
|
||||
including \c type, \c vared, \c pushd and \c popd are implemented as shellscript
|
||||
functions in fish.
|
||||
- Mathematical calculations, regex matching, generating lists of numbers
|
||||
and many other funtions can easily be done in external programs. They
|
||||
should not be supported internally by the shell.
|
||||
|
||||
The law of minimalism does not imply that a large feature set is
|
||||
bad. So long as a feature is not part of the shell itself, but a
|
||||
separate command or at least a shellscript function, bloat is fine.
|
||||
|
||||
\section conf Configurability is the root of all evil
|
||||
|
||||
Every configuration option in a program is a place where the program
|
||||
is too stupid to figure out for itself what the user really wants, and
|
||||
should be considered a failiure of both the program and the programmer
|
||||
who implemented it.
|
||||
|
||||
Rationale:
|
||||
|
||||
Different configuration options are a nightmare to maintain, since the
|
||||
number of potential bugs caused by specific configuration combinations
|
||||
quickly becomes an issue. Configuration options often imply
|
||||
assumptions about the code which change when reimplementing the code,
|
||||
causing issues with backwards compatibility. But mostly, configuration
|
||||
options should be avoided since they simply should not exist, as the
|
||||
program should be smart enough to do what is best, or at least a good
|
||||
enough approximation of it.
|
||||
|
||||
Examples:
|
||||
|
||||
- Fish allows the user to set various syntax highlighting colors. This is needed because fish does not know what colors the terminal uses by default, which might make some things unreadable. The proper solution would be for text color preferences to be defined centrally by the user for all programs, and for the terminal emulator to send these color properties to fish.
|
||||
- Fish does not allow you to set the history filename, the number of history entries, different language substyles or any number of other common shell configuration options.
|
||||
|
||||
A special note on the evils of configurability is the long list of
|
||||
very useful features found in some shells, that are not turned on by
|
||||
default. Both zsh and bash support command specific completions, but
|
||||
no such completions are shipped with bash by default, and they are
|
||||
turned of by default in zsh. Other features that zsh support that are
|
||||
disabled by default include tab-completion of strings containing
|
||||
wildcards, a sane completion pager and a history file.
|
||||
|
||||
\section user The law of user focus
|
||||
|
||||
When designing a program, one should first think about how to make a
|
||||
intuitive and powerful program. Implementation issues should only be
|
||||
considered once a user interface has been designed.
|
||||
|
||||
Rationale:
|
||||
|
||||
This design rule is different than the others, since it describes how
|
||||
one should go about designing new features, not what the features
|
||||
should be. The problem with focusing on what can be done, and what is
|
||||
easy to do, is that to much of the implementation is exposed. This
|
||||
means that the user must know a great deal about the underlying system
|
||||
to be able to guess how the shell works, it also means that the
|
||||
language will often be rather low-level.
|
||||
|
||||
Examples:
|
||||
|
||||
- There should only be one type of input to the shell, lists of commands. Loops, conditionals and variable assignments are all performed through regular commands.
|
||||
- The differences between builtin commands, shellscript functions and builtin commands should be made as small as possible. Builtins and shellscript functions should have exactly the same types of argument expansion as other commands, should be possible to use in any position in a pipeline, and should support any io redirection.
|
||||
- Instead of forking when performing command substitution to provide a fake variable scope, all fish commands are performed from the same process, and fish instead supports true scoping
|
||||
- All blocks end with the \c end builtin
|
||||
|
||||
\section disc The law of discoverability
|
||||
|
||||
A program should be designed to make its features as
|
||||
easy as possible to discover for the user.
|
||||
|
||||
Rationale:
|
||||
|
||||
A program whose features are discoverable turns a new user into an
|
||||
expert in a shorter span of time, since the user will become an expert
|
||||
on the program simply by using it.
|
||||
|
||||
The main benefit of a graphical program over a command line-based
|
||||
program is discoverability. In a graphical program, one can discover
|
||||
all the common features by simply looking at the user interface and
|
||||
guessing what the different buttons, menus and other widgets do. The
|
||||
traditional way to discover features in commandline programs is
|
||||
through manual pages. This requires both that the user starts to use a
|
||||
different program, and the she/he then remembers the new information
|
||||
until the next time she/he uses the same program.
|
||||
|
||||
Examples:
|
||||
|
||||
- Everything should be tab-completable, and every tab completion should have a description
|
||||
- Every syntax error and error in a builtin command should contain an error message describing what went wrong and a relevant help page. Whenever possible, errors should be flagged red by the syntax highlighter.
|
||||
- The help manual should be easy to read, easily available from the shell, complete and contain many examples
|
||||
- The language should be uniform, so that once the user understands the command/argument syntax, he will know the whole language, and be able to use tab-completion to discover new featues.
|
||||
|
||||
*/
|
||||
@@ -1,4 +1,4 @@
|
||||
\section dirh dirh
|
||||
\section dirh dirh - print directory history
|
||||
|
||||
\subsection dirh-synopsis Synopsis
|
||||
<tt>dirh</tt>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section dirs dirs
|
||||
\section dirs dirs - print directory stack
|
||||
|
||||
\subsection dirs-synopsis Synopsis
|
||||
<tt>dirs</tt>
|
||||
|
||||
2574
doc_src/doc.hdr
2574
doc_src/doc.hdr
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
\section else else - execute command if a condition is not met.
|
||||
\section else else - execute command if a condition is not met
|
||||
|
||||
\subsection else-synopsis Synopsis
|
||||
<tt>if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end;</tt>
|
||||
<tt>if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end</tt>
|
||||
|
||||
\subsection else-description Description
|
||||
<tt>if</tt> will execute the command CONDITION. If the commands exit
|
||||
status is zero, the command COMMAND_TRUE will execute. If it is
|
||||
not zero and COMMAND_FALSE is specified, COMMAND_FALSE will be
|
||||
executed.
|
||||
<tt>if</tt> will execute the command CONDITION. If the condition's exit
|
||||
status is 0, the commands COMMANDS_TRUE will execute. If it is not 0 and
|
||||
<tt>else</tt> is given, COMMANDS_FALSE will be executed. Hint: use
|
||||
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions.
|
||||
|
||||
\subsection else-example Example
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
\section end end - end a block of commands.
|
||||
|
||||
\subsection end-synopsis Synopsis
|
||||
<pre>for VARNAME in [VALUES...]; COMMANDS; end
|
||||
if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end
|
||||
while CONDITION; COMMANDS; end
|
||||
switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end
|
||||
<pre>
|
||||
begin; [COMMANDS...] end
|
||||
if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end
|
||||
while CONDITION; COMMANDS...; end
|
||||
for VARNAME in [VALUES...]; COMMANDS...; end
|
||||
switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end
|
||||
</pre>
|
||||
|
||||
\subsection end-description Description
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section exec exec - Execute command in current process
|
||||
\section exec exec - execute command in current process
|
||||
|
||||
\subsection exec-synopsis Synopsis
|
||||
<tt>exec COMMAND [OPTIONS...]</tt>
|
||||
|
||||
136
doc_src/faq.hdr
Normal file
136
doc_src/faq.hdr
Normal file
@@ -0,0 +1,136 @@
|
||||
/** \page faq Frequently asked questions
|
||||
|
||||
- <a href='#faq-cwd-symlink'>Why does cd, pwd and other fish commands always resolve symlinked directories to their canonical path?</a>
|
||||
- <a href='#faq-cd-autocomplete'>Why does the cd command autocompletion list the subdirectories of my home directory as completions?</a>
|
||||
- <a href='#faq-cd-implicit'>I accidentally entered a directory path and fish changed directory. What happened?</a>
|
||||
- <a href='#faq-open'>The open command doesn't work.</a>
|
||||
- <a href='#faq-default'>How do I make fish my default shell?</a>
|
||||
- <a href='#faq-titlebar'>I'm seeing weird output before each prompt when using screen. What's wrong?</a>
|
||||
- <a href='#faq-greeting'>How do I change the greeting message?</a>
|
||||
|
||||
<hr>
|
||||
|
||||
\section faq-cwd-symlink Why does cd, $PWD and and various fish commands always resolve symlinked directories to their canonical path?
|
||||
|
||||
<i>
|
||||
For example if ~/images is a symlink to ~/Documents/Images, if I write
|
||||
'cd images', my prompt will say ~/D/Images, not ~/images.
|
||||
</i>
|
||||
|
||||
Because it is impossible to consistently keep symlinked directories
|
||||
unresolved. It is indeed possible to do this partially, and many other
|
||||
shells do so. But it was felt there are enough serious corner cases
|
||||
that this is a bad idea. Most such issues have to do with how '..' is
|
||||
handled, and are varitations of the following example:
|
||||
|
||||
Writing <code>cd images; ls ..</code> given the above directory
|
||||
structure would list the contents of ~/Documents, not of ~, even
|
||||
though using <code>cd ..</code> changes the current direcotry to ~,
|
||||
and the prompt, the pwd builtin and many other directory information
|
||||
sources suggest that the the current directory is ~/images and it's
|
||||
parent is ~. This issue is not possible to fix without either making
|
||||
every single command into a builtin, breaking Unix semantics or
|
||||
implementing kludges in every single command.
|
||||
|
||||
This issue can also be seen when doing IO redirection.
|
||||
|
||||
Another related issue is that many programs that operate on recursive
|
||||
directory trees, like the find command, silently ignore symlinked
|
||||
directories. For example, <code>find $PWD -name '*.txt'</code>
|
||||
silently fails in shells that don't resolve symlinked paths.
|
||||
|
||||
<hr>
|
||||
|
||||
\section faq-cd-autocomplete Why does the cd command autocompletion list the subdirectories of my home directory as completions?
|
||||
|
||||
Because they are completions. In fish, if you specify a relative
|
||||
directory to the cd command, i.e. any path that does not start with
|
||||
either './' or '/', the environment variable CDPATH will be examined, and any
|
||||
directories in this path is used as a base direcotry. To disable this
|
||||
feature, write <code>set CDPATH .</code> on the commandline.
|
||||
|
||||
<hr>
|
||||
|
||||
\section faq-cd-implicit I accidentally entered a directory path and fish changed directory. What happened?
|
||||
|
||||
If fish is unable to locate a command with a given name, fish will
|
||||
test if a directory of that name exists. If it does, it is implicitly
|
||||
assumed that you want to change working directory. For example, the
|
||||
fastest way to switch to your home directory is to simply type
|
||||
<code>~</code>.
|
||||
|
||||
<hr>
|
||||
|
||||
\section faq-open The open command doesn't work.
|
||||
|
||||
The open command uses the mimetype database and the .desktop files
|
||||
used by Gnome and KDE to identify filetypes and default actions. If
|
||||
at least one of these two desktops are installed, but the open command is
|
||||
not working, this probably means that the relevant files are installed
|
||||
in a nonstandard location. Please contact the <a
|
||||
href='mailto:fish-users@lists.sf.net'>fish mailing list</a>, and
|
||||
hopefully this can be resolved.
|
||||
|
||||
\section faq-default How do I make fish my default shell?
|
||||
|
||||
If you installed fish manually (e.g. by compiling it, not by using a
|
||||
package manager), you first need to add fish to the list of shells by
|
||||
executing the following command (assuming you installed fish in
|
||||
/usr/local) as root:
|
||||
|
||||
\section faq-titlebar I'm seeing weird output before each prompt when using screen. What's wrong?
|
||||
|
||||
Quick answer:
|
||||
|
||||
Run the following command in fish:
|
||||
|
||||
<pre>
|
||||
echo function fish_title;end ~/.config/fish/config.fish
|
||||
</pre>
|
||||
|
||||
Problem solved!
|
||||
|
||||
The long answer:
|
||||
|
||||
Fish is trying to set the titlebar message of your terminal. While
|
||||
screen itself supports this feature, your terminal does
|
||||
not. Unfortuntaly, when the underlying terminal doesn't support
|
||||
setting the titlebar, screen simply passes through the escape codes
|
||||
and text to the underlying terminal instead of ignoring them. It is
|
||||
impossible detect and resolve this problem from inside fish since fish
|
||||
has no way of knowing what the underlying terminal type is. For now,
|
||||
the only way to fix this is to unset the titlebar message, as
|
||||
suggested above.
|
||||
|
||||
Note that fish has a default titlebar message, which will be used if
|
||||
the fish_title function is undefined. So simply unsetting the
|
||||
fish_title function will not work.
|
||||
|
||||
|
||||
<code>echo /usr/local/bin/fish >>/etc/shells</code>
|
||||
|
||||
If you installed a prepackaged version of fish, the package manager
|
||||
should have already done this for you.
|
||||
|
||||
In order to change your default shell, type:
|
||||
|
||||
<code>chsh -s /usr/bin/fish</code>
|
||||
|
||||
You may need to adjust the above path to e.g. /usr/local/bin/fish.
|
||||
|
||||
You will need to log out and back in again for the change to take
|
||||
effect.
|
||||
|
||||
<hr>
|
||||
|
||||
\section faq-greeting How do I change the greeting message?
|
||||
|
||||
Change the value of the variable fish_greeting. For example, to remove
|
||||
the greeting use:
|
||||
|
||||
<pre>
|
||||
set fish_greeting
|
||||
</pre>
|
||||
|
||||
|
||||
*/
|
||||
18
doc_src/fish.txt
Normal file
18
doc_src/fish.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
\section fish fish - the friendly interactive shell
|
||||
|
||||
\subsection fish-synopsis Synopsis
|
||||
fish [-h] [-v] [-c command] [FILE [ARGUMENTS...]]
|
||||
|
||||
\subsection fish-description Description
|
||||
|
||||
A commandline shell written mainly with interactive use in mind. The full manual is available <a href='index.html'>in html</a> by using the <a href='#help'>help</a> command from inside fish.
|
||||
|
||||
- <code>-c</code> or <code>--command=COMMANDS</code> evaluate the specified commands instead of reading from the commandline
|
||||
- <code>-d</code> or <code>--debug-level=DEBUG_LEVEL</code> specify the verbosity level of fish. A higher number means higher verbosity. The default level is 1.
|
||||
- <code>-h</code> or <code>--help</code> display help and exit
|
||||
- <code>-i</code> or <code>--interactive</code> specify that fish is to run in interactive mode
|
||||
- <code>-l</code> or <code>--login</code> specify that fish is to run as a login shell
|
||||
- <code>-n</code> or <code>--no-execute</code> do not execute any commands, only perform syntax checking
|
||||
- <code>-p</code> or <code>--profile=PROFILE_FILE</code> when fish exits, output timing information on all executed commands to the specified file
|
||||
- <code>-v</code> or <code>--version</code> display version and exit
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section fish_pager fish_pager - Internal command used by fish
|
||||
\section fish_pager fish_pager - internal command used by fish
|
||||
|
||||
\subsection fish_pager-description Description
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section fishd fishd - Universal variable daemon
|
||||
\section fishd fishd - universal variable daemon
|
||||
|
||||
\subsection fishd-synopsis Synopsis
|
||||
<tt>fishd [(-h|--help|-v|--version)]</tt>
|
||||
@@ -18,13 +17,14 @@ When no clients are connected, fishd will automatically shut down.
|
||||
|
||||
\subsection fishd-files Files
|
||||
|
||||
~/.fishd.HOSTNAME permanent storage location for universal variable
|
||||
data. The data is stored as a set of \c set and \c set_export commands
|
||||
such as would be parsed by fishd. If an instance of fishd is running
|
||||
(which is generally the case), manual modifications to ~/.fishd.HOSTNAME
|
||||
will be lost. Do NOT edit this file manually!
|
||||
\c ~/.config/fish/fishd.HOSTNAME permanent storage location for universal
|
||||
variable data. The data is stored as a set of \c set and \c set_export
|
||||
commands such as would be parsed by fishd. The file must always be
|
||||
stored in ASCII format. If an instance of fishd is running (which is
|
||||
generally the case), manual modifications to ~/.fishd.HOSTNAME will be
|
||||
lost. Do NOT edit this file manually!
|
||||
|
||||
/tmp/fishd.socket.USERNAME the socket which fishd uses to communicate
|
||||
\c /tmp/fishd.socket.USERNAME the socket which fishd uses to communicate
|
||||
with all clients.
|
||||
|
||||
/tmp/fishd.log.USERNAME the fishd log file
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
\section for for - perform a set of commands multiple times.
|
||||
|
||||
\subsection for-synopsis Synopsis
|
||||
<tt>for VARNAME in [VALUES...]; [COMMANDS...]; end</tt>
|
||||
<tt>for VARNAME in [VALUES...]; COMMANDS...; end</tt>
|
||||
|
||||
\subsection for-description Description
|
||||
<tt>for</tt> is a loop construct. It will perform the commands specified
|
||||
by <tt>COMMANDS</tt> multiple times. Each time the environment variable
|
||||
specified by <tt>VARNAME</tt> is assigned a new value from <tt>VALUES</tt>.
|
||||
<tt>for</tt> is a loop construct. It will perform the commands specified by
|
||||
COMMANDS multiple times. Each time the environment variable specified by
|
||||
VARNAME is assigned a new value from VALUES. If VALUES is empty, COMMANDS will
|
||||
not be executed at all.
|
||||
|
||||
\subsection for-example Example
|
||||
|
||||
@@ -17,7 +17,9 @@ The command
|
||||
|
||||
would output:
|
||||
|
||||
<pre>foo
|
||||
<pre>
|
||||
foo
|
||||
bar
|
||||
baz</pre>
|
||||
baz
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
\subsection function-description Description
|
||||
|
||||
- \c -b or \c --key-binding specifies that the function is a key biding. Key binding functions work exactly like regular functions except that they can not be tab-completed, and may contain the '-' character.
|
||||
- <code>-d DESCRIPTION</code> or \c --description=DESCRIPTION is a description of what the function does, suitable as a completion description
|
||||
- <code>-j PID</code> or <code> --on-job-exit PID</code> tells fish to run this function when the job with group id PID exits. Instead of PID, the string 'caller' can be specified. This is only legal when in a command substitution, and will result in the handler being triggered by the exit of the job which created this command substitution.
|
||||
- <code>-p PID</code> or <code> --on-process-exit PID</code> tells fish to run this function when the fish child process with process id PID exits
|
||||
@@ -29,7 +28,8 @@ are inserted into the environment <a href="index.html#variables-arrays">variable
|
||||
|
||||
\subsection function-example Example
|
||||
|
||||
<pre>function ll
|
||||
<pre>
|
||||
function ll
|
||||
ls -l $argv
|
||||
end
|
||||
</pre>
|
||||
|
||||
@@ -11,7 +11,7 @@ This builtin command is used to print or erase functions.
|
||||
- <code>-d DESCRIPTION</code> or <code>--description=DESCRIPTION</code> change the description of this function
|
||||
- <code>-e</code> or <code>--erase</code> causes the specified functions to be erased.
|
||||
- <code>-h</code> or <code>--help</code> display a help message and exit
|
||||
- <code>-n</code> or <code>--names</code> list only the names of all defined functions
|
||||
- <code>-n</code> or <code>--names</code> list only the names of all defined functions, not their definition
|
||||
- <code>-q</code> or <code>--query</code> test if the specified functions exist. Does not output anything, but the builtins exit status is the number of functions specified that were not defined.
|
||||
|
||||
The default behavior of \c functions when called with no arguments,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section help help - Display fish documentation
|
||||
\section help help - display fish documentation
|
||||
|
||||
\subsection help-synopsis Synopsis
|
||||
<tt>help [SECTION]</tt>
|
||||
@@ -8,8 +7,11 @@
|
||||
|
||||
The \c help command is used to display a section of the fish help documentation.
|
||||
|
||||
If the BROWSER environment variable is set, it will be used to display
|
||||
the documentation, otherwise fish will search for a suitable browser.
|
||||
If the BROWSER environment variable is set, it will be used to display the
|
||||
documentation, otherwise fish will search for a suitable browser.
|
||||
|
||||
Note also that most builtin commands display their help in the terminal when
|
||||
given the <tt>--help</tt> option.
|
||||
|
||||
\subsection help-example Example
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
\section if if - Conditionally execute a command
|
||||
\section if if - conditionally execute a command
|
||||
|
||||
\subsection if-synopsis Synopsis
|
||||
<tt>if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end;</tt>
|
||||
<tt>if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end</tt>
|
||||
|
||||
\subsection if-description Description
|
||||
<tt>if</tt> will execute the command CONDITION. If the commands exit
|
||||
status is zero, the command COMMAND_TRUE will execute. If it is
|
||||
not zero and COMMAND_FALSE is specified, COMMAND_FALSE will be
|
||||
executed.
|
||||
<tt>if</tt> will execute the command CONDITION. If the condition's exit
|
||||
status is 0, the commands COMMANDS_TRUE will execute. If it is not 0 and
|
||||
<tt>else</tt> is given, COMMANDS_FALSE will be executed. Hint: use
|
||||
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions.
|
||||
|
||||
\subsection if-example Example
|
||||
|
||||
|
||||
1367
doc_src/index.hdr
Normal file
1367
doc_src/index.hdr
Normal file
File diff suppressed because it is too large
Load Diff
12
doc_src/isatty.txt
Normal file
12
doc_src/isatty.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
\section isatty isatty - test if the specidied file descriptor is a tty
|
||||
|
||||
\subsection isatty-synopsis Synopsis
|
||||
<tt>isatty [FILE DESCRIPTOR]</tt>
|
||||
|
||||
where FILE DESCRIPTOR may be either the number of a file descriptor, or one
|
||||
of the strings stdin, stdout and stderr.
|
||||
|
||||
If the specified file descriptor is a tty, the exit status of the
|
||||
command is zero, otherwise, it is non-zero.
|
||||
|
||||
|
||||
989
doc_src/license.hdr
Normal file
989
doc_src/license.hdr
Normal file
@@ -0,0 +1,989 @@
|
||||
/** \page license Licenses
|
||||
|
||||
Fish Copyright (C) 2005 Axel Liljencrantz. Fish is released under the
|
||||
GNU General Public License, version 2. The license agreement is
|
||||
included below.
|
||||
|
||||
Fish contains code under the BSD license, namely versions of the
|
||||
two functions strlcat and strlcpy, modified for use with wide
|
||||
character strings. This code is copyrighted by Todd C. Miller. The
|
||||
license agreement is included below.
|
||||
|
||||
The XSel command, written and copyrighted by Conrad Parker, is
|
||||
distributed together with, and used by fish. It is released under the MIT
|
||||
license. The license agreement is included below.
|
||||
|
||||
The xdgmime library, written and copyrighted by Red Hat, Inc, is used
|
||||
by the mimedb command, which is a part of fish. It is released under
|
||||
the LGPL. The license agreement is included below.
|
||||
|
||||
Fish contains code from the glibc library, namely the wcstok
|
||||
function. This code is licensed under the LGPL. The license agreement
|
||||
is included below.
|
||||
|
||||
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="SEC1" HREF="gpl.html#TOC1">GNU GENERAL PUBLIC LICENSE</A></H2>
|
||||
<P>
|
||||
Version 2, June 1991
|
||||
|
||||
</P>
|
||||
|
||||
<PRE>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
</PRE>
|
||||
|
||||
|
||||
<H2><A NAME="SEC2" HREF="gpl.html#TOC2">Preamble</A></H2>
|
||||
|
||||
<P>
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU 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. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), 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.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
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.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
|
||||
For example, if you distribute copies of 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 show them these terms so they know their
|
||||
rights.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
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.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
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.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
</P>
|
||||
<P>
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
|
||||
</P>
|
||||
|
||||
|
||||
<H2><A NAME="SEC3" HREF="gpl.html#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
|
||||
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>0.</STRONG>
|
||||
This License 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 derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
<P>
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>1.</STRONG>
|
||||
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 License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
<P>
|
||||
|
||||
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.
|
||||
<P>
|
||||
|
||||
<STRONG>2.</STRONG>
|
||||
You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
<P>
|
||||
|
||||
<DL>
|
||||
|
||||
<DT>
|
||||
<DD>
|
||||
<STRONG>a)</STRONG>
|
||||
You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
</DD>
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>
|
||||
<DD>
|
||||
<STRONG>b)</STRONG>
|
||||
You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
</DD>
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>
|
||||
<DD>
|
||||
<STRONG>c)</STRONG>
|
||||
If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary 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
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
</DD>
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
<P>
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
<P>
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>3.</STRONG>
|
||||
You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
|
||||
<!-- we use this doubled UL to get the sub-sections indented, -->
|
||||
<!-- while making the bullets as unobvious as possible. -->
|
||||
|
||||
<DL>
|
||||
<DT>
|
||||
|
||||
<DD>
|
||||
<STRONG>a)</STRONG>
|
||||
Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
</DD>
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>
|
||||
<DD>
|
||||
<STRONG>b)</STRONG>
|
||||
Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
</DD>
|
||||
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>
|
||||
<DD>
|
||||
<STRONG>c)</STRONG>
|
||||
Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
</DD>
|
||||
</DT>
|
||||
</DL>
|
||||
<P>
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
<P>
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
<P>
|
||||
|
||||
<STRONG>4.</STRONG>
|
||||
You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>5.</STRONG>
|
||||
You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing 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 for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>6.</STRONG>
|
||||
|
||||
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.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>7.</STRONG>
|
||||
If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
<P>
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
<P>
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
<P>
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>8.</STRONG>
|
||||
If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>9.</STRONG>
|
||||
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.
|
||||
<P>
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this 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
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>10.</STRONG>
|
||||
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.
|
||||
|
||||
|
||||
|
||||
<P><STRONG>NO WARRANTY</STRONG></P>
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>11.</STRONG>
|
||||
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.
|
||||
|
||||
<P>
|
||||
|
||||
<STRONG>12.</STRONG>
|
||||
|
||||
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.
|
||||
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
|
||||
<h2>License for wcslcat and wcslcpy</h2>
|
||||
|
||||
\c fish also contains small amounts of code under the BSD
|
||||
license, namely versions of the two functions strlcat and strlcpy,
|
||||
modified for use with wide character strings. This code is copyrighted
|
||||
by Todd C. Miller.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
<HR>
|
||||
|
||||
<h2>License for XSel</h2>
|
||||
|
||||
The XSel command, written and copyrighted by Conrad Parker, is
|
||||
distributed together with \c fish.
|
||||
|
||||
|
||||
It is Copyright (C) 2001 Conrad Parker <conrad@vergenet.net>
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software
|
||||
and its documentation for any purpose is hereby granted without fee,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation. No representations are made about the
|
||||
suitability of this software for any purpose. It is provided "as is"
|
||||
without express or implied warranty.
|
||||
|
||||
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="SEC1" HREF="#TOC1">GNU LESSER GENERAL PUBLIC LICENSE</A></H2>
|
||||
|
||||
<P>
|
||||
Version 2.1, February 1999
|
||||
|
||||
<P>
|
||||
<PRE>
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
</PRE>
|
||||
|
||||
|
||||
<H2><A NAME="SEC2" HREF="#TOC2">Preamble</A></H2>
|
||||
|
||||
<P>
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
<P>
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
<P>
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
<P>
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
<P>
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
<P>
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
<P>
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
<P>
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
<P>
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
<P>
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
<P>
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
<P>
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
<P>
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
<P>
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
<P>
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
<P>
|
||||
|
||||
<H2><A NAME="SEC3" HREF="#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
|
||||
|
||||
|
||||
<P>
|
||||
<STRONG>0.</STRONG>
|
||||
This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
<P>
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
<P>
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
<P>
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
<P>
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
<P>
|
||||
<STRONG>1.</STRONG>
|
||||
You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
<P>
|
||||
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.
|
||||
<P>
|
||||
<STRONG>2.</STRONG>
|
||||
|
||||
You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
<P>
|
||||
<UL>
|
||||
<LI><STRONG>a)</STRONG>
|
||||
The modified work must itself be a software library.
|
||||
<LI><STRONG>b)</STRONG>
|
||||
You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
<LI><STRONG>c)</STRONG>
|
||||
You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
<LI><STRONG>d)</STRONG>
|
||||
|
||||
If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
<P>
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
<P>
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
<P>
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
<P>
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
</UL>
|
||||
<P>
|
||||
<STRONG>3.</STRONG>
|
||||
|
||||
You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
<P>
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
<P>
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
<P>
|
||||
<STRONG>4.</STRONG>
|
||||
You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
<P>
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
<P>
|
||||
<STRONG>5.</STRONG>
|
||||
|
||||
A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
<P>
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
<P>
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
<P>
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
<P>
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
<P>
|
||||
<STRONG>6.</STRONG>
|
||||
As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
<P>
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
<P>
|
||||
<UL>
|
||||
<LI><STRONG>a)</STRONG> Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
<LI><STRONG>b)</STRONG> Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
<LI><STRONG>c)</STRONG> Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
<LI><STRONG>d)</STRONG> If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
<LI><STRONG>e)</STRONG> Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
</UL>
|
||||
<P>
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
<P>
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
<P>
|
||||
<STRONG>7.</STRONG> You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
<P>
|
||||
<UL>
|
||||
<LI><STRONG>a)</STRONG> Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
<LI><STRONG>b)</STRONG> Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
</UL>
|
||||
<P>
|
||||
<STRONG>8.</STRONG> You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
<P>
|
||||
<STRONG>9.</STRONG>
|
||||
You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
<P>
|
||||
<STRONG>10.</STRONG>
|
||||
Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
<P>
|
||||
<STRONG>11.</STRONG>
|
||||
If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
<P>
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
<P>
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
<P>
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
<P>
|
||||
<STRONG>12.</STRONG>
|
||||
If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
<P>
|
||||
<STRONG>13.</STRONG>
|
||||
The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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.
|
||||
<P>
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this 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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
<P>
|
||||
|
||||
<STRONG>14.</STRONG>
|
||||
If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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.
|
||||
<P>
|
||||
<STRONG>NO WARRANTY</STRONG>
|
||||
<P>
|
||||
<STRONG>15.</STRONG>
|
||||
BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
<P>
|
||||
<STRONG>16.</STRONG>
|
||||
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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
<P>
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section mimedb mimedb - Lookup file information via the mime database
|
||||
\section mimedb mimedb - lookup file information via the mime database
|
||||
|
||||
\subsection mimedb-synopsis Synopsis
|
||||
<tt>mimedb [OPTIONS] FILES...</tt>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
\section nextd nextd
|
||||
\section nextd nextd - move forward through directory history
|
||||
|
||||
\subsection nextd-synopsis Synopsis
|
||||
<tt>nextd [-l | --list] [pos]</tt>
|
||||
|
||||
\subsection nextd-description Description <tt>nextd</tt> moves
|
||||
forwards <tt>pos</tt> positions in the history of visited directories;
|
||||
if the end of the history has been hit, a warning is printed. If the
|
||||
<code>-l></code> or <code>--list</code> flag is specified, the current
|
||||
\subsection nextd-description Description
|
||||
<tt>nextd</tt> moves forwards <tt>pos</tt> positions in the history of visited
|
||||
directories; if the end of the history has been hit, a warning is printed. If
|
||||
the <code>-l></code> or <code>--list</code> flag is specified, the current
|
||||
history is also displayed.
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
|
||||
\section not not - Negate the exit status of a job
|
||||
\section not not - negate the exit status of a job
|
||||
|
||||
\subsection not-synopsis Synopsis
|
||||
<tt>not COMMAND [OPTIONS...]</tt>
|
||||
<tt>not COMMAND [OPTIONS...]</tt>
|
||||
|
||||
\subsection not-description Description
|
||||
|
||||
The \c not builtin is used to negate the exit status of another command.
|
||||
|
||||
|
||||
\subsection not-example Example
|
||||
|
||||
The following code reports an error and exits if no file named spoon can be found.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section open open - Open file in it's default application
|
||||
\section open open - open file in it's default application
|
||||
|
||||
\subsection open-synopsis Synopsis
|
||||
<tt>open FILES...</tt>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
\section or or - Conditionally execute a command
|
||||
\section or or - conditionally execute a command
|
||||
|
||||
\subsection or-synopsis Synopsis
|
||||
<tt>COMMAND1; or COMMAND2</tt>
|
||||
|
||||
\subsection or-description Description
|
||||
|
||||
The \c or builtin is used to execute a command if the current exit status (as set by the last previous command) is non-zero
|
||||
The \c or builtin is used to execute a command if the current exit
|
||||
status (as set by the last previous command) is not 0.
|
||||
|
||||
The or command does not change the current exit status.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section popd popd
|
||||
\section popd popd - move through directory stack
|
||||
|
||||
\subsection popd-synopsis Synopsis
|
||||
<tt>popd</tt>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section prevd prevd
|
||||
\section prevd prevd - move backward through direcotry history
|
||||
|
||||
\subsection prevd-synopsis Synopsis
|
||||
<tt>prevd [-l | --list] [pos]</tt>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section psub psub - Perform process substitution
|
||||
\section psub psub - perform process substitution
|
||||
|
||||
\subsection psub-synopsis Synopsis
|
||||
<tt>COMMAND1 (COMMAND2|psub) </tt>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section pushd pushd
|
||||
\section pushd pushd - push directory to directory stack
|
||||
|
||||
\subsection pushd-synopsis Synopsis
|
||||
<tt>pushd [DIRECTORY]</tt>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section random random - Generate random number
|
||||
\section random random - generate random number
|
||||
|
||||
\subsection random-synopsis Synopsis
|
||||
<tt>random [SEED]</tt>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
\section return return - Stop the innermost currently evaluated function
|
||||
\section return return - stop the innermost currently evaluated function
|
||||
|
||||
\subsection return-synopsis Synopsis
|
||||
<tt>function NAME; [COMMANDS...] return [STATUS]; [COMMANDS...] end</tt>
|
||||
<tt>function NAME; [COMMANDS...;] return [STATUS]; [COMMANDS...;] end</tt>
|
||||
|
||||
\subsection return-description Description
|
||||
|
||||
@@ -17,9 +16,11 @@ function.
|
||||
|
||||
\subsection return-example Example
|
||||
The following code is an implementation of the false command as a fish function
|
||||
<p>
|
||||
<pre>function false
|
||||
return 1
|
||||
end</pre>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
function false
|
||||
return 1
|
||||
end
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
\section set set - Handle environment variables.
|
||||
\section set set - handle environment variables.
|
||||
|
||||
\subsection set-synopsis Synopsis
|
||||
<pre>set [SCOPE_OPTIONS]
|
||||
<pre>
|
||||
set [SCOPE_OPTIONS]
|
||||
set [OPTIONS] VARIABLE_NAME VALUES...
|
||||
set [OPTIONS] VARIABLE_NAME[INDICES]... VALUES...
|
||||
set (-q | --query) [SCOPE_OPTIONS] VARIABLE_NAMES...
|
||||
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME
|
||||
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME[INDICES]... </pre>
|
||||
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME[INDICES]...
|
||||
</pre>
|
||||
|
||||
The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_NAME</code> the values <code>VALUES...</code>.
|
||||
|
||||
@@ -15,7 +17,7 @@ The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_N
|
||||
- <code>-l</code> or <code>--local</code> forces the specified environment variable to be given a scope that is local to the current block, even if a variable with the given name exists and is non-local
|
||||
- <code>-g</code> or <code>--global</code> causes the specified environment variable to be given a global scope. Non-global variables disappear when the block they belong to ends
|
||||
- <code>-U</code> or <code>--universal</code> causes the specified environment variable to be given a universal scope. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell.
|
||||
- <code>-n</code> or <code>--names</code> List only the names of all defined variables
|
||||
- <code>-n</code> or <code>--names</code> List only the names of all defined variables, not their value
|
||||
- <code>-q</code> or <code>--query</code> test if the specified variable names are defined. Does not output anything, but the builtins exit status is the number of variables specified that were not defined.
|
||||
- <code>-u</code> or <code>--unexport</code> causes the specified environment not to be exported to child processes
|
||||
- <code>-x</code> or <code>--export</code> causes the specified environment variable to be exported to child processes
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section set_color set_color - Set the terminal color
|
||||
\section set_color set_color - set the terminal color
|
||||
|
||||
\subsection set_color-synopsis Synopsis
|
||||
<tt>set_color [-v --version] [-h --help] [-b --background COLOR] [COLOR]</tt>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
\section source . - Evaluate contents of file.
|
||||
\section source . - evaluate contents of file.
|
||||
|
||||
\subsection source-synopsis Synopsis
|
||||
<tt>. FILENAME</tt>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section status status - Display fish runtime information
|
||||
\section status status - query fish runtime information
|
||||
|
||||
\subsection status-synopsis Synopsis
|
||||
<tt>status [OPTION]</tt>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
\section switch switch - conditionally execute a block of commands
|
||||
|
||||
\subsection switch-synopsis Synopsis
|
||||
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end</tt>
|
||||
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end</tt>
|
||||
|
||||
\subsection switch-description Description
|
||||
|
||||
@@ -22,12 +21,17 @@ Note that fish does not fall through on case statements. Though the
|
||||
syntax may look a bit like C switch statements, it behaves more like
|
||||
the case stamantes of traditional shells.
|
||||
|
||||
Also note that command substitutions in a case statement will be
|
||||
evaluated even if it's body is not taken. This may seem
|
||||
counterintuitive at first, but it is unavoidable, since it would be
|
||||
impossible to know if a case command will evaluate to true before all
|
||||
forms of parameter expansion have been performed for the case command.
|
||||
|
||||
\subsection switch-example Example
|
||||
|
||||
If the variable \$animal contains the name of an animal, the
|
||||
following code would attempt to classify it:
|
||||
If the variable \$animal contains the name of an animal, the following
|
||||
code would attempt to classify it:
|
||||
|
||||
<p>
|
||||
<pre>
|
||||
switch $animal
|
||||
case cat
|
||||
@@ -42,10 +46,7 @@ switch $animal
|
||||
echo I have no idea what a $animal is
|
||||
end
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
If the above code was run with \c \$animal set to \c whale, the output
|
||||
would be \c mammal.
|
||||
|
||||
</p>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
\section trap trap - perform an action when the shell receives a signal
|
||||
|
||||
\subsection trap-synopsis Synopsis
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section type type - Indicate how a name would be interpreted if used as a command name
|
||||
\section type type - indicate how a name would be interpreted if used as a command name
|
||||
|
||||
\subsection type-synopsis Synopsis
|
||||
<tt>type [OPTIONS] name [name ...]</tt>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section ulimit ulimit - Set or get the shells resource usage limits
|
||||
\section ulimit ulimit - set or get the shells resource usage limits
|
||||
|
||||
\subsection ulimit-synopsis Synopsis
|
||||
<tt>ulimit [OPTIONS] [LIMIT]</tt>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section umask umask - Set or get the shells resource usage limits
|
||||
\section umask umask - set or get the shells resource usage limits
|
||||
|
||||
\subsection umask-synopsis Synopsis
|
||||
<code>umask [OPTIONS] [MASK]</code>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
\section vared vared - Interactively edit the value of an environment variable
|
||||
\section vared vared - interactively edit the value of an environment variable
|
||||
|
||||
\subsection vared-synopsis Synopsis
|
||||
<tt>vared VARIABLE_NAME</tt>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
\section while while - perform a command multiple times
|
||||
|
||||
\subsection while-synopsis Synopsis
|
||||
<tt>while CONDITION; COMMANDS; end</tt>
|
||||
<tt>while CONDITION; COMMANDS...; end</tt>
|
||||
|
||||
\subsection while-synopsis Synopsis
|
||||
The <tt>while</tt> builtin causes fish to continually execute the command COMMANDS while the command CONDITION returns with status 0.
|
||||
\subsection while-description Description
|
||||
The <tt>while</tt> builtin causes fish to continually execute CONDITION and
|
||||
execute COMMANDS as long as CONDITION returned with status 0. If CONDITION is
|
||||
false on the first time, COMMANDS will not be executed at all. Hints: use
|
||||
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions; more
|
||||
complex control can be achieved with <tt>while true</tt> containing a
|
||||
<a href="#break">break</a>.
|
||||
|
||||
\subsection while-example Example
|
||||
|
||||
<tt>while test -f foo.txt; echo file exists; sleep 10; end</tt>
|
||||
|
||||
causes fish to print the line 'file exists' at 10 second intervals as long as the file foo.txt exists.
|
||||
causes fish to print the line 'file exists' at 10 second intervals as long as
|
||||
the file foo.txt exists.
|
||||
|
||||
51
env.c
51
env.c
@@ -59,7 +59,7 @@
|
||||
/**
|
||||
Command used to start fishd
|
||||
*/
|
||||
#define FISHD_CMD L"if which fishd 2>/dev/null >/dev/null; fishd ^/tmp/fishd.log.%s; end"
|
||||
#define FISHD_CMD L"fishd ^/tmp/fishd.log.%s"
|
||||
|
||||
/**
|
||||
Value denoting a null string
|
||||
@@ -452,11 +452,34 @@ static void setup_path()
|
||||
al_destroy( &l );
|
||||
}
|
||||
|
||||
static void env_set_defaults()
|
||||
{
|
||||
if( !env_get( L"USER" ) )
|
||||
{
|
||||
struct passwd *pw = getpwuid( getuid());
|
||||
wchar_t *unam = str2wcs( pw->pw_name );
|
||||
env_set( L"USER", unam, ENV_GLOBAL );
|
||||
free( unam );
|
||||
}
|
||||
if( !env_get( L"HOME" ) )
|
||||
{
|
||||
wchar_t *unam = env_get( L"USER" );
|
||||
char *unam_narrow = wcs2str( unam );
|
||||
struct passwd *pw = getpwnam( unam_narrow );
|
||||
wchar_t *dir = str2wcs( pw->pw_dir );
|
||||
env_set( L"HOME", dir, ENV_GLOBAL );
|
||||
free( dir );
|
||||
free( unam_narrow );
|
||||
}
|
||||
}
|
||||
|
||||
void env_init()
|
||||
{
|
||||
char **p;
|
||||
struct passwd *pw;
|
||||
wchar_t *uname;
|
||||
wchar_t *version;
|
||||
|
||||
|
||||
sb_init( &dyn_var );
|
||||
b_init( &export_buffer );
|
||||
@@ -468,6 +491,7 @@ void env_init()
|
||||
|
||||
hash_put( &env_read_only, L"status", L"" );
|
||||
hash_put( &env_read_only, L"history", L"" );
|
||||
hash_put( &env_read_only, L"version", L"" );
|
||||
hash_put( &env_read_only, L"_", L"" );
|
||||
hash_put( &env_read_only, L"LINES", L"" );
|
||||
hash_put( &env_read_only, L"COLUMNS", L"" );
|
||||
@@ -555,12 +579,23 @@ void env_init()
|
||||
env_set( L"USER", uname, ENV_GLOBAL | ENV_EXPORT );
|
||||
free( uname );
|
||||
}
|
||||
|
||||
/*
|
||||
Set up the version variable
|
||||
*/
|
||||
version = str2wcs( PACKAGE_VERSION );
|
||||
env_set( L"version", version, ENV_GLOBAL );
|
||||
free( version );
|
||||
|
||||
env_universal_init( env_get( L"FISHD_SOCKET_DIR"),
|
||||
env_get( L"USER" ),
|
||||
&start_fishd,
|
||||
&universal_callback );
|
||||
|
||||
|
||||
/*
|
||||
Set correct defaults for e.g. USER and HOME variables
|
||||
*/
|
||||
env_set_defaults();
|
||||
}
|
||||
|
||||
void env_destroy()
|
||||
@@ -683,7 +718,7 @@ int env_set( const wchar_t *key,
|
||||
|
||||
env_universal_set( key, val, export );
|
||||
is_universal = 1;
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -711,6 +746,7 @@ int env_set( const wchar_t *key,
|
||||
(var_mode & ENV_GLOBAL) )
|
||||
{
|
||||
node = ( var_mode & ENV_GLOBAL )?global_env:top;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -936,7 +972,7 @@ wchar_t *env_get( const wchar_t *key )
|
||||
wchar_t *item;
|
||||
|
||||
CHECK( key, 0 );
|
||||
|
||||
|
||||
if( wcscmp( key, L"history" ) == 0 )
|
||||
{
|
||||
wchar_t *current;
|
||||
@@ -951,15 +987,11 @@ wchar_t *env_get( const wchar_t *key )
|
||||
sb_append( &dyn_var, current );
|
||||
}
|
||||
|
||||
for( i=add_current; i<8; i++ )
|
||||
for( i=add_current;; i++ )
|
||||
{
|
||||
wchar_t *next = history_get( i-add_current );
|
||||
if( !next )
|
||||
{
|
||||
/*
|
||||
This is not an error - it simply means the user has
|
||||
a short history
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -967,6 +999,7 @@ wchar_t *env_get( const wchar_t *key )
|
||||
sb_append( &dyn_var, ARRAY_SEP_STR );
|
||||
sb_append( &dyn_var, next );
|
||||
}
|
||||
|
||||
return (wchar_t *)dyn_var.buff;
|
||||
}
|
||||
else if( wcscmp( key, L"COLUMNS" )==0 )
|
||||
|
||||
7
env.h
7
env.h
@@ -80,8 +80,8 @@ void env_destroy();
|
||||
*/
|
||||
|
||||
int env_set( const wchar_t *key,
|
||||
const wchar_t *val,
|
||||
int mode );
|
||||
const wchar_t *val,
|
||||
int mode );
|
||||
|
||||
|
||||
/**
|
||||
@@ -94,7 +94,7 @@ int env_set( const wchar_t *key,
|
||||
wchar_t *env_get( const wchar_t *key );
|
||||
|
||||
/**
|
||||
Returns 1 if the specified key exists. This can't be reliable done
|
||||
Returns 1 if the specified key exists. This can't be reliably done
|
||||
using env_get, since env_get returns null for 0-element arrays
|
||||
|
||||
\param key The name of the variable to remove
|
||||
@@ -129,7 +129,6 @@ char **env_export_arr( int recalc );
|
||||
|
||||
/**
|
||||
Insert all variable names into l. These are not copies of the strings and should not be freed after use.
|
||||
|
||||
*/
|
||||
void env_get_names( array_list_t *l, int flags );
|
||||
|
||||
|
||||
@@ -164,7 +164,6 @@ static void callback( int type, const wchar_t *name, const wchar_t *val )
|
||||
{
|
||||
if( type == BARRIER_REPLY )
|
||||
{
|
||||
debug( 3, L"Got barrier reply" );
|
||||
barrier_reply = 1;
|
||||
}
|
||||
else
|
||||
@@ -194,7 +193,7 @@ static void check_connection()
|
||||
|
||||
env_universal_server.fd = -1;
|
||||
env_universal_server.killme=0;
|
||||
sb_clear( &env_universal_server.input );
|
||||
env_universal_server.input.used=0;
|
||||
env_universal_read_all();
|
||||
}
|
||||
}
|
||||
@@ -212,6 +211,7 @@ static void reconnect()
|
||||
debug( 3, L"Get new fishd connection" );
|
||||
|
||||
init = 0;
|
||||
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
|
||||
env_universal_server.fd = get_socket(1);
|
||||
init = 1;
|
||||
if( env_universal_server.fd >= 0 )
|
||||
@@ -226,26 +226,21 @@ void env_universal_init( wchar_t * p,
|
||||
void (*sf)(),
|
||||
void (*cb)( int type, const wchar_t *name, const wchar_t *val ))
|
||||
{
|
||||
debug( 3, L"env_universal_init()" );
|
||||
path=p;
|
||||
user=u;
|
||||
start_fishd=sf;
|
||||
external_callback = cb;
|
||||
|
||||
connection_init( &env_universal_server, -1 );
|
||||
|
||||
env_universal_server.fd = -1;
|
||||
env_universal_server.killme = 0;
|
||||
env_universal_server.fd = get_socket(1);
|
||||
memset (&env_universal_server.wstate, '\0', sizeof (mbstate_t));
|
||||
q_init( &env_universal_server.unsent );
|
||||
env_universal_common_init( &callback );
|
||||
sb_init( &env_universal_server.input );
|
||||
env_universal_read_all();
|
||||
init = 1;
|
||||
if( env_universal_server.fd >= 0 )
|
||||
{
|
||||
env_universal_barrier();
|
||||
}
|
||||
debug( 3, L"end env_universal_init()" );
|
||||
}
|
||||
|
||||
void env_universal_destroy()
|
||||
@@ -259,17 +254,11 @@ void env_universal_destroy()
|
||||
{
|
||||
wperror( L"fcntl" );
|
||||
}
|
||||
try_send_all( &env_universal_server );
|
||||
|
||||
if( close( env_universal_server.fd ) )
|
||||
{
|
||||
wperror( L"close" );
|
||||
}
|
||||
try_send_all( &env_universal_server );
|
||||
}
|
||||
|
||||
|
||||
connection_destroy( &env_universal_server );
|
||||
env_universal_server.fd =-1;
|
||||
q_destroy( &env_universal_server.unsent );
|
||||
sb_destroy( &env_universal_server.input );
|
||||
env_universal_common_destroy();
|
||||
init = 0;
|
||||
}
|
||||
@@ -283,8 +272,6 @@ int env_universal_read_all()
|
||||
if( !init)
|
||||
return 0;
|
||||
|
||||
debug( 3, L"env_universal_read_all()" );
|
||||
|
||||
if( env_universal_server.fd == -1 )
|
||||
{
|
||||
reconnect();
|
||||
@@ -312,7 +299,6 @@ wchar_t *env_universal_get( const wchar_t *name )
|
||||
|
||||
CHECK( name, 0 );
|
||||
|
||||
debug( 3, L"env_universal_get( \"%ls\" )", name );
|
||||
return env_universal_common_get( name );
|
||||
}
|
||||
|
||||
@@ -323,7 +309,6 @@ int env_universal_get_export( const wchar_t *name )
|
||||
|
||||
CHECK( name, 0 );
|
||||
|
||||
debug( 3, L"env_universal_get_export()" );
|
||||
return env_universal_common_get_export( name );
|
||||
}
|
||||
|
||||
@@ -367,7 +352,7 @@ void env_universal_barrier()
|
||||
FD_SET( env_universal_server.fd, &fds );
|
||||
select( env_universal_server.fd+1, 0, &fds, 0, 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Wait for barrier reply
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <wctype.h>
|
||||
#include <iconv.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
@@ -69,6 +70,21 @@
|
||||
*/
|
||||
#define PARSE_ERR L"Unable to parse universal variable message: '%ls'"
|
||||
|
||||
/**
|
||||
ERROR string for internal buffered reader
|
||||
*/
|
||||
#define ENV_UNIVERSAL_ERROR 0x100
|
||||
|
||||
/**
|
||||
EAGAIN string for internal buffered reader
|
||||
*/
|
||||
#define ENV_UNIVERSAL_AGAIN 0x101
|
||||
|
||||
/**
|
||||
EOF string for internal buffered reader
|
||||
*/
|
||||
#define ENV_UNIVERSAL_EOF 0x102
|
||||
|
||||
/**
|
||||
A variable entry. Stores the value of a variable and whether it
|
||||
should be exported. Obviously, it needs to be allocated large
|
||||
@@ -110,9 +126,163 @@ static int get_names_show_exported;
|
||||
static int get_names_show_unexported;
|
||||
|
||||
|
||||
wchar_t *utf2wcs( const char *in )
|
||||
{
|
||||
iconv_t cd=(iconv_t) -1;
|
||||
int i,j;
|
||||
|
||||
wchar_t *out;
|
||||
|
||||
char *to_name[]=
|
||||
{
|
||||
"wchar_t", "WCHAR_T", "wchar", "WCHAR", 0
|
||||
}
|
||||
;
|
||||
|
||||
char *from_name[]=
|
||||
{
|
||||
"utf-8", "UTF-8", "utf8", "UTF8", 0
|
||||
}
|
||||
;
|
||||
|
||||
size_t in_len = strlen( in );
|
||||
size_t out_len = sizeof( wchar_t )*(in_len+1);
|
||||
size_t nconv;
|
||||
char *nout;
|
||||
|
||||
out = malloc( out_len );
|
||||
nout = (char *)out;
|
||||
|
||||
if( !out )
|
||||
return 0;
|
||||
|
||||
for( i=0; to_name[i]; i++ )
|
||||
{
|
||||
for( j=0; from_name[j]; j++ )
|
||||
{
|
||||
cd = iconv_open ( to_name[i], from_name[j] );
|
||||
|
||||
if( cd != (iconv_t) -1)
|
||||
{
|
||||
goto start_conversion;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_conversion:
|
||||
|
||||
if (cd == (iconv_t) -1)
|
||||
{
|
||||
/* Something went wrong. */
|
||||
debug( 0, L"Could not perform utf-8 conversion" );
|
||||
if(errno != EINVAL)
|
||||
wperror( L"iconv_open" );
|
||||
|
||||
/* Terminate the output string. */
|
||||
free(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
nconv = iconv( cd, (char **)&in, &in_len, &nout, &out_len );
|
||||
|
||||
if (nconv == (size_t) -1)
|
||||
{
|
||||
debug( 0, L"Error while converting from utf string" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
*((wchar_t *) nout) = L'\0';
|
||||
|
||||
if (iconv_close (cd) != 0)
|
||||
wperror (L"iconv_close");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
char *wcs2utf( const wchar_t *in )
|
||||
{
|
||||
iconv_t cd=(iconv_t) -1;
|
||||
int i,j;
|
||||
|
||||
char *char_in = (char *)in;
|
||||
char *out;
|
||||
|
||||
char *from_name[]=
|
||||
{
|
||||
"wchar_t", "WCHAR_T", "wchar", "WCHAR", 0
|
||||
}
|
||||
;
|
||||
|
||||
char *to_name[]=
|
||||
{
|
||||
"utf-8", "UTF-8", "utf8", "UTF8", 0
|
||||
}
|
||||
;
|
||||
|
||||
size_t in_len = wcslen( in );
|
||||
size_t out_len = sizeof( char )*( (MAX_UTF8_BYTES*in_len)+1);
|
||||
size_t nconv;
|
||||
char *nout;
|
||||
|
||||
out = malloc( out_len );
|
||||
nout = (char *)out;
|
||||
in_len *= sizeof( wchar_t );
|
||||
|
||||
if( !out )
|
||||
return 0;
|
||||
|
||||
for( i=0; to_name[i]; i++ )
|
||||
{
|
||||
for( j=0; from_name[j]; j++ )
|
||||
{
|
||||
cd = iconv_open ( to_name[i], from_name[j] );
|
||||
|
||||
if( cd != (iconv_t) -1)
|
||||
{
|
||||
goto start_conversion;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_conversion:
|
||||
|
||||
if (cd == (iconv_t) -1)
|
||||
{
|
||||
/* Something went wrong. */
|
||||
debug( 0, L"Could not perform utf-8 conversion" );
|
||||
if(errno != EINVAL)
|
||||
wperror( L"iconv_open" );
|
||||
|
||||
/* Terminate the output string. */
|
||||
free(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nconv = iconv( cd, &char_in, &in_len, &nout, &out_len );
|
||||
|
||||
|
||||
if (nconv == (size_t) -1)
|
||||
{
|
||||
debug( 0, L"%d %d", in_len, out_len );
|
||||
debug( 0, L"Error while converting from to string" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
*nout = '\0';
|
||||
|
||||
if (iconv_close (cd) != 0)
|
||||
wperror (L"iconv_close");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void env_universal_common_init( void (*cb)(int type, const wchar_t *key, const wchar_t *val ) )
|
||||
{
|
||||
debug( 3, L"Init env_universal_common" );
|
||||
callback = cb;
|
||||
hash_init( &env_universal_var, &hash_wcs_func, &hash_wcs_cmp );
|
||||
}
|
||||
@@ -134,69 +304,118 @@ void env_universal_common_destroy()
|
||||
hash_destroy( &env_universal_var );
|
||||
}
|
||||
|
||||
static int read_byte( connection_t *src )
|
||||
{
|
||||
|
||||
if( src->buffer_consumed >= src->buffer_used )
|
||||
{
|
||||
|
||||
int res;
|
||||
|
||||
res = read( src->fd, src->buffer, ENV_UNIVERSAL_BUFFER_SIZE );
|
||||
|
||||
// debug(4, L"Read chunk '%.*s'", res, src->buffer );
|
||||
|
||||
if( res < 0 )
|
||||
{
|
||||
|
||||
if( errno == EAGAIN ||
|
||||
errno == EINTR )
|
||||
{
|
||||
return ENV_UNIVERSAL_AGAIN;
|
||||
}
|
||||
|
||||
return ENV_UNIVERSAL_ERROR;
|
||||
|
||||
}
|
||||
|
||||
if( res == 0 )
|
||||
{
|
||||
return ENV_UNIVERSAL_EOF;
|
||||
}
|
||||
|
||||
src->buffer_consumed = 0;
|
||||
src->buffer_used = res;
|
||||
}
|
||||
|
||||
return src->buffer[src->buffer_consumed++];
|
||||
|
||||
}
|
||||
|
||||
|
||||
void read_message( connection_t *src )
|
||||
{
|
||||
while( 1 )
|
||||
{
|
||||
char b;
|
||||
int read_res = read( src->fd, &b, 1 );
|
||||
wchar_t res=0;
|
||||
|
||||
if( read_res < 0 )
|
||||
int ib = read_byte( src );
|
||||
char b;
|
||||
|
||||
switch( ib )
|
||||
{
|
||||
if( errno != EAGAIN &&
|
||||
errno != EINTR )
|
||||
case ENV_UNIVERSAL_AGAIN:
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
case ENV_UNIVERSAL_ERROR:
|
||||
{
|
||||
debug( 2, L"Read error on fd %d, set killme flag", src->fd );
|
||||
wperror( L"read" );
|
||||
if( debug_level > 2 )
|
||||
wperror( L"read" );
|
||||
src->killme = 1;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( read_res == 0 )
|
||||
{
|
||||
src->killme = 1;
|
||||
debug( 3, L"Fd %d has reached eof, set killme flag", src->fd );
|
||||
if( src->input.used > 0 )
|
||||
|
||||
case ENV_UNIVERSAL_EOF:
|
||||
{
|
||||
debug( 1,
|
||||
L"Universal variable connection closed while reading command. Partial command recieved: '%ls'",
|
||||
(wchar_t *)src->input.buff );
|
||||
src->killme = 1;
|
||||
debug( 3, L"Fd %d has reached eof, set killme flag", src->fd );
|
||||
if( src->input.used > 0 )
|
||||
{
|
||||
char c = 0;
|
||||
b_append( &src->input, &c, 1 );
|
||||
debug( 1,
|
||||
L"Universal variable connection closed while reading command. Partial command recieved: '%s'",
|
||||
(wchar_t *)src->input.buff );
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int sz = mbrtowc( &res, &b, 1, &src->wstate );
|
||||
b = (char)ib;
|
||||
|
||||
if( sz == -1 )
|
||||
{
|
||||
debug( 1, L"Error while reading universal variable after '%ls'", (wchar_t *)src->input.buff );
|
||||
wperror( L"mbrtowc" );
|
||||
}
|
||||
else if( sz > 0 )
|
||||
if( b == '\n' )
|
||||
{
|
||||
if( res == L'\n' )
|
||||
wchar_t *msg;
|
||||
|
||||
b = 0;
|
||||
b_append( &src->input, &b, 1 );
|
||||
|
||||
msg = utf2wcs( src->input.buff );
|
||||
|
||||
/*
|
||||
Before calling parse_message, we must empty reset
|
||||
everything, since the callback function could
|
||||
potentially call read_message.
|
||||
*/
|
||||
src->input.used=0;
|
||||
|
||||
if( msg )
|
||||
{
|
||||
/*
|
||||
Before calling parse_message, we must empty reset
|
||||
everything, since the callback function could
|
||||
potentially call read_message.
|
||||
*/
|
||||
|
||||
wchar_t *msg = wcsdup( (wchar_t *)src->input.buff );
|
||||
sb_clear( &src->input );
|
||||
memset (&src->wstate, '\0', sizeof (mbstate_t));
|
||||
|
||||
|
||||
parse_message( msg, src );
|
||||
free( msg );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_append_char( &src->input, res );
|
||||
debug( 0, _(L"Could not convert message '%s' to wide character string"), src->input.buff );
|
||||
}
|
||||
|
||||
free( msg );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
b_append( &src->input, &b, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,7 +455,7 @@ static int match( const wchar_t *msg, const wchar_t *cmd )
|
||||
static void parse_message( wchar_t *msg,
|
||||
connection_t *src )
|
||||
{
|
||||
debug( 3, L"parse_message( %ls );", msg );
|
||||
// debug( 3, L"parse_message( %ls );", msg );
|
||||
|
||||
if( msg[0] == L'#' )
|
||||
return;
|
||||
@@ -343,7 +562,16 @@ static int try_send( message_t *msg,
|
||||
L"before write of %d chars to fd %d", strlen(msg->body), fd );
|
||||
|
||||
int res = write( fd, msg->body, strlen(msg->body) );
|
||||
|
||||
|
||||
if( res != -1 )
|
||||
{
|
||||
debug( 4, L"Wrote message '%s'", msg->body );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug( 4, L"Failed to write message '%s'", msg->body );
|
||||
}
|
||||
|
||||
if( res == -1 )
|
||||
{
|
||||
switch( errno )
|
||||
@@ -352,10 +580,11 @@ static int try_send( message_t *msg,
|
||||
return 0;
|
||||
|
||||
default:
|
||||
debug( 1,
|
||||
debug( 2,
|
||||
L"Error while sending universal variable message to fd %d. Closing connection",
|
||||
fd );
|
||||
wperror( L"write" );
|
||||
if( debug_level > 2 )
|
||||
wperror( L"write" );
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -371,9 +600,9 @@ static int try_send( message_t *msg,
|
||||
|
||||
void try_send_all( connection_t *c )
|
||||
{
|
||||
debug( 3,
|
||||
/* debug( 3,
|
||||
L"Send all updates to connection on fd %d",
|
||||
c->fd );
|
||||
c->fd );*/
|
||||
while( !q_empty( &c->unsent) )
|
||||
{
|
||||
switch( try_send( (message_t *)q_peek( &c->unsent), c->fd ) )
|
||||
@@ -383,7 +612,7 @@ void try_send_all( connection_t *c )
|
||||
break;
|
||||
|
||||
case 0:
|
||||
debug( 1,
|
||||
debug( 4,
|
||||
L"Socket full, send rest later" );
|
||||
return;
|
||||
|
||||
@@ -394,6 +623,33 @@ void try_send_all( connection_t *c )
|
||||
}
|
||||
}
|
||||
|
||||
static wchar_t *full_escape( const wchar_t *in )
|
||||
{
|
||||
string_buffer_t out;
|
||||
sb_init( &out );
|
||||
for( ; *in; in++ )
|
||||
{
|
||||
if( *in < 32 )
|
||||
{
|
||||
sb_printf( &out, L"\\x%.2x", *in );
|
||||
}
|
||||
else if( *in < 128 )
|
||||
{
|
||||
sb_append_char( &out, *in );
|
||||
}
|
||||
else if( *in < 65536 )
|
||||
{
|
||||
sb_printf( &out, L"\\u%.4x", *in );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_printf( &out, L"\\U%.8x", *in );
|
||||
}
|
||||
}
|
||||
return (wchar_t *)out.buff;
|
||||
}
|
||||
|
||||
|
||||
message_t *create_message( int type,
|
||||
const wchar_t *key_in,
|
||||
const wchar_t *val_in )
|
||||
@@ -402,10 +658,18 @@ message_t *create_message( int type,
|
||||
|
||||
char *key=0;
|
||||
size_t sz;
|
||||
|
||||
// debug( 4, L"Crete message of type %d", type );
|
||||
|
||||
if( key_in )
|
||||
{
|
||||
key = wcs2str(key_in);
|
||||
if( wcsvarname( key_in ) )
|
||||
{
|
||||
debug( 0, L"Illegal variable name: '%ls'", key_in );
|
||||
return 0;
|
||||
}
|
||||
|
||||
key = wcs2utf(key_in);
|
||||
if( !key )
|
||||
{
|
||||
debug( 0,
|
||||
@@ -426,11 +690,11 @@ message_t *create_message( int type,
|
||||
val_in=L"";
|
||||
}
|
||||
|
||||
wchar_t *esc = escape(val_in,1);
|
||||
wchar_t *esc = full_escape( val_in );
|
||||
if( !esc )
|
||||
break;
|
||||
|
||||
char *val = wcs2str(esc );
|
||||
char *val = wcs2utf(esc );
|
||||
free(esc);
|
||||
|
||||
sz = strlen(type==SET?SET_MBS:SET_EXPORT_MBS) + strlen(key) + strlen(val) + 4;
|
||||
@@ -495,6 +759,9 @@ message_t *create_message( int type,
|
||||
|
||||
if( msg )
|
||||
msg->count=0;
|
||||
|
||||
// debug( 4, L"Message body is '%s'", msg->body );
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -572,3 +839,22 @@ void enqueue_all( connection_t *c )
|
||||
try_send_all( c );
|
||||
}
|
||||
|
||||
|
||||
void connection_init( connection_t *c, int fd )
|
||||
{
|
||||
memset (c, 0, sizeof (connection_t));
|
||||
c->fd = fd;
|
||||
b_init( &c->input );
|
||||
q_init( &c->unsent );
|
||||
c->buffer_consumed = c->buffer_used = 0;
|
||||
}
|
||||
|
||||
void connection_destroy( connection_t *c)
|
||||
{
|
||||
q_destroy( &c->unsent );
|
||||
b_destroy( &c->input );
|
||||
if( close( c->fd ) )
|
||||
{
|
||||
wperror( L"close" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ enum
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
The size of the buffer used for reading from the socket
|
||||
*/
|
||||
#define ENV_UNIVERSAL_BUFFER_SIZE 1024
|
||||
|
||||
/**
|
||||
This struct represents a connection between a universal variable server/client
|
||||
*/
|
||||
@@ -66,16 +71,28 @@ typedef struct connection
|
||||
Set to one when this connection should be killed
|
||||
*/
|
||||
int killme;
|
||||
/**
|
||||
The state used for character conversions
|
||||
*/
|
||||
mbstate_t wstate;
|
||||
/**
|
||||
The input string. Input from the socket goes here. When a
|
||||
newline is encountered, the buffer is parsed and cleared.
|
||||
*/
|
||||
string_buffer_t input;
|
||||
buffer_t input;
|
||||
|
||||
/**
|
||||
The read buffer.
|
||||
*/
|
||||
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
|
||||
|
||||
/**
|
||||
Number of bytes that have already been consumed.
|
||||
*/
|
||||
int buffer_consumed;
|
||||
|
||||
/**
|
||||
Number of bytes that have been read into the buffer.
|
||||
*/
|
||||
int buffer_used;
|
||||
|
||||
|
||||
/**
|
||||
Link to the next connection
|
||||
*/
|
||||
@@ -147,5 +164,8 @@ int env_universal_common_get_export( const wchar_t *name );
|
||||
*/
|
||||
void enqueue_all( connection_t *c );
|
||||
|
||||
void connection_init( connection_t *c, int fd );
|
||||
void connection_destroy( connection_t *c);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,13 +3,6 @@
|
||||
#
|
||||
# @configure_input@
|
||||
|
||||
#
|
||||
# Set default search paths for completions and shellscript functions
|
||||
#
|
||||
|
||||
set -g fish_function_path ~/.fish.d/functions @sysconfdir@/fish.d/functions @datadir@/fish/functions
|
||||
set -g fish_complete_path ~/.fish.d/completions @sysconfdir@/fish.d/completions @datadir@/fish/completions
|
||||
|
||||
#
|
||||
# Set default field separators
|
||||
#
|
||||
@@ -66,6 +59,8 @@ end
|
||||
# Load additional initialization files
|
||||
#
|
||||
|
||||
for i in fish.d/*.fish
|
||||
. $i
|
||||
end
|
||||
if test -d include
|
||||
for i in include/*.fish
|
||||
. $i
|
||||
end
|
||||
end
|
||||
@@ -1,110 +0,0 @@
|
||||
#
|
||||
# Initializations that should only be performed when in interactive mode
|
||||
#
|
||||
# @configure_input@
|
||||
|
||||
if not status --is-interactive
|
||||
exit
|
||||
end
|
||||
|
||||
#
|
||||
# Print a greeting
|
||||
#
|
||||
|
||||
printf (_ 'Welcome to fish, the friendly interactive shell\n')
|
||||
printf (_ 'Type %shelp%s for instructions on how to use fish\n') (set_color green) (set_color normal)
|
||||
|
||||
#
|
||||
# Set exit message
|
||||
#
|
||||
|
||||
function fish_on_exit -d (_ "Commands to execute when fish exits") --on-process %self
|
||||
printf (_ "Good bye\n")
|
||||
end
|
||||
|
||||
#
|
||||
# Set INPUTRC to something nice
|
||||
#
|
||||
# We override INPUTRC if already set, since it may be set by a shell
|
||||
# other than fish, which may use a different file. The new value should
|
||||
# be exported, since the fish inputrc file plays nice with other files
|
||||
# by including them when found.
|
||||
# Give priority to the default file installed with fish in
|
||||
# @sysconfdir@/fish_inputrc.
|
||||
#
|
||||
|
||||
for i in ~/.fish_inputrc @sysconfdir@/fish_inputrc ~/.inputrc /etc/inputrc
|
||||
if test -f $i
|
||||
set -xg INPUTRC $i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Set various defaults using these throwaway functions
|
||||
#
|
||||
|
||||
function set_default -d "Set an universal variable, unless it has already been set"
|
||||
if not set -q $argv[1]
|
||||
set -U -- $argv
|
||||
end
|
||||
if not set -q $argv[1]
|
||||
set -g -- $argv
|
||||
end
|
||||
end
|
||||
|
||||
function set_exported_default -d "Set an exported universal variable, unless it has already been set"
|
||||
if not set -q $argv[1]
|
||||
set -Ux -- $argv
|
||||
end
|
||||
if not set -q $argv[1]
|
||||
set -gx -- $argv
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Regular syntax highlighting colors
|
||||
set_default fish_color_normal normal
|
||||
set_default fish_color_command green
|
||||
set_default fish_color_redirection normal
|
||||
set_default fish_color_comment red
|
||||
set_default fish_color_error red --bold
|
||||
set_default fish_color_escape cyan
|
||||
set_default fish_color_operator cyan
|
||||
set_default fish_color_quote brown
|
||||
set_default fish_color_valid_path --underline
|
||||
|
||||
set_default fish_color_cwd green
|
||||
|
||||
# Background color for matching quotes and parenthesis
|
||||
set_default fish_color_match cyan
|
||||
|
||||
# Background color for search matches
|
||||
set_default fish_color_search_match purple
|
||||
|
||||
# Pager colors
|
||||
set_default fish_pager_color_prefix cyan
|
||||
set_default fish_pager_color_completion normal
|
||||
set_default fish_pager_color_description normal
|
||||
set_default fish_pager_color_progress cyan
|
||||
|
||||
#
|
||||
# Directory history colors
|
||||
#
|
||||
|
||||
set_default fish_color_history_current cyan
|
||||
|
||||
|
||||
#
|
||||
# Setup the CDPATH variable
|
||||
#
|
||||
|
||||
set_default CDPATH . ~
|
||||
|
||||
#
|
||||
# Remove temporary functions for setting default variable values
|
||||
#
|
||||
|
||||
functions -e set_exported_default
|
||||
functions -e set_default
|
||||
146
exec.c
146
exec.c
@@ -69,6 +69,10 @@ pid_t getpgid( pid_t pid );
|
||||
*/
|
||||
#define FORK_ERROR _( L"Could not create child process - exiting" )
|
||||
|
||||
/**
|
||||
Base open mode to pass to calls to open
|
||||
*/
|
||||
#define BASE_MASK 0666
|
||||
|
||||
/**
|
||||
List of all pipes used by internal pipes. These must be closed in
|
||||
@@ -272,7 +276,7 @@ static int handle_child_io( io_data_t *io, int exit_on_error )
|
||||
case IO_FILE:
|
||||
{
|
||||
if( (tmp=wopen( io->param1.filename,
|
||||
io->param2.flags, 0777 ) )==-1 )
|
||||
io->param2.flags, BASE_MASK ) )==-1 )
|
||||
{
|
||||
debug( 1,
|
||||
FILE_ERROR,
|
||||
@@ -441,7 +445,9 @@ static void launch_process( process_t *p )
|
||||
{
|
||||
// debug( 1, L"exec '%ls'", p->argv[0] );
|
||||
|
||||
execve (wcs2str(p->actual_cmd), wcsv2strv( (const wchar_t **) p->argv), env_export_arr( 0 ) );
|
||||
execve ( wcs2str(p->actual_cmd),
|
||||
wcsv2strv( (const wchar_t **) p->argv),
|
||||
env_export_arr( 0 ) );
|
||||
debug( 0,
|
||||
_( L"Failed to execute process '%ls'" ),
|
||||
p->actual_cmd );
|
||||
@@ -525,7 +531,7 @@ static io_data_t *io_transmogrify( io_data_t * in )
|
||||
{
|
||||
int fd;
|
||||
|
||||
if( (fd=wopen( in->param1.filename, in->param2.flags, 0777 ) )==-1 )
|
||||
if( (fd=wopen( in->param1.filename, in->param2.flags, BASE_MASK ) )==-1 )
|
||||
{
|
||||
debug( 1,
|
||||
FILE_ERROR,
|
||||
@@ -576,7 +582,7 @@ static void internal_exec_helper( const wchar_t *def,
|
||||
*/
|
||||
if( io && !io_internal )
|
||||
{
|
||||
proc_set_last_status( 1 );
|
||||
proc_set_last_status( STATUS_EXEC_FAIL );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -607,23 +613,23 @@ static int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if( j->job_control )
|
||||
if( job_get_flag( j, JOB_CONTROL ) )
|
||||
{
|
||||
int new_pgid=0;
|
||||
|
||||
if (!j->pgid)
|
||||
{
|
||||
new_pgid=1;
|
||||
j->pgid = p->pid;
|
||||
}
|
||||
|
||||
if( setpgid (p->pid, j->pgid) )
|
||||
{
|
||||
{
|
||||
if( getpgid( p->pid) != j->pgid && print_errors )
|
||||
{
|
||||
debug( 1,
|
||||
_( L"Could not send process %d from group %d to group %d" ),
|
||||
p->pid,
|
||||
_( L"Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d" ),
|
||||
p->pid,
|
||||
p->argv[0],
|
||||
j->job_id,
|
||||
j->command,
|
||||
getpgid( p->pid),
|
||||
j->pgid );
|
||||
wperror( L"setpgid" );
|
||||
@@ -636,7 +642,7 @@ static int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||
j->pgid = getpid();
|
||||
}
|
||||
|
||||
if( j->terminal && j->fg )
|
||||
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
|
||||
{
|
||||
if( tcsetpgrp (0, j->pgid) && print_errors )
|
||||
{
|
||||
@@ -671,13 +677,16 @@ void exec( job_t *j )
|
||||
*/
|
||||
int exec_error=0;
|
||||
|
||||
int needs_keepalive = 0;
|
||||
process_t keepalive;
|
||||
|
||||
|
||||
CHECK( j, );
|
||||
|
||||
CHECK_BLOCK();
|
||||
|
||||
if( no_exec )
|
||||
return;
|
||||
|
||||
|
||||
|
||||
sigemptyset( &chldset );
|
||||
sigaddset( &chldset, SIGCHLD );
|
||||
|
||||
@@ -729,7 +738,7 @@ void exec( job_t *j )
|
||||
}
|
||||
else
|
||||
{
|
||||
j->constructed=1;
|
||||
job_set_flag( j, JOB_CONSTRUCTED, 1 );
|
||||
j->first_process->completed=1;
|
||||
return;
|
||||
}
|
||||
@@ -753,6 +762,53 @@ void exec( job_t *j )
|
||||
j->io = io_add( j->io, &pipe_write );
|
||||
|
||||
signal_block();
|
||||
|
||||
/*
|
||||
See if we need to create a group keepalive process. This is a
|
||||
process that we create to make sure that the process group
|
||||
doesn't die accidentally, and is needed when a block/function is
|
||||
inside a pipeline.
|
||||
*/
|
||||
|
||||
if( job_get_flag( j, JOB_CONTROL ) )
|
||||
{
|
||||
for( p=j->first_process; p; p = p->next )
|
||||
{
|
||||
if( (p->type == INTERNAL_BLOCK ) ||
|
||||
(p->type == INTERNAL_FUNCTION ) )
|
||||
{
|
||||
if( p->next )
|
||||
{
|
||||
needs_keepalive = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( needs_keepalive )
|
||||
{
|
||||
keepalive.pid = fork();
|
||||
|
||||
if( keepalive.pid == 0 )
|
||||
{
|
||||
keepalive.pid = getpid();
|
||||
set_child_group( j, &keepalive, 1 );
|
||||
pause();
|
||||
exit(0);
|
||||
}
|
||||
else if( keepalive.pid < 0 )
|
||||
{
|
||||
/* The fork failed. */
|
||||
debug( 0, FORK_ERROR );
|
||||
wperror (L"fork");
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_child_group( j, &keepalive, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This loop loops over every process_t in the job, starting it as
|
||||
@@ -761,7 +817,7 @@ void exec( job_t *j )
|
||||
|
||||
The loop also has to handle pipelining between the jobs.
|
||||
*/
|
||||
|
||||
|
||||
for( p=j->first_process; p; p = p->next )
|
||||
{
|
||||
mypipe[1]=-1;
|
||||
@@ -816,18 +872,27 @@ void exec( job_t *j )
|
||||
{
|
||||
case INTERNAL_FUNCTION:
|
||||
{
|
||||
const wchar_t * orig_def;
|
||||
wchar_t * def=0;
|
||||
|
||||
signal_unblock();
|
||||
orig_def = function_get_definition( p->argv[0] );
|
||||
signal_block();
|
||||
|
||||
wchar_t * def = halloc_register( j, wcsdup( function_get_definition( p->argv[0] )));
|
||||
if( orig_def )
|
||||
{
|
||||
def = halloc_register( j, wcsdup(orig_def) );
|
||||
}
|
||||
if( def == 0 )
|
||||
{
|
||||
debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
parser_push_block( FUNCTION_CALL );
|
||||
|
||||
current_block->param2.function_call_process = p;
|
||||
current_block->param1.function_name = halloc_register( current_block, wcsdup( p->argv[0] ) );
|
||||
current_block->param1.function_call_name = halloc_register( current_block, wcsdup( p->argv[0] ) );
|
||||
|
||||
parse_util_set_argv( p->argv+1 );
|
||||
|
||||
@@ -889,7 +954,7 @@ void exec( job_t *j )
|
||||
case IO_FILE:
|
||||
{
|
||||
builtin_stdin=wopen( in->param1.filename,
|
||||
in->param2.flags, 0777 );
|
||||
in->param2.flags, BASE_MASK );
|
||||
if( builtin_stdin == -1 )
|
||||
{
|
||||
debug( 1,
|
||||
@@ -939,8 +1004,8 @@ void exec( job_t *j )
|
||||
|
||||
builtin_out_redirect = has_fd( j->io, 1 );
|
||||
builtin_err_redirect = has_fd( j->io, 2 );
|
||||
fg = j->fg;
|
||||
j->fg = 0;
|
||||
fg = job_get_flag( j, JOB_FOREGROUND );
|
||||
job_set_flag( j, JOB_FOREGROUND, 0 );
|
||||
|
||||
signal_unblock();
|
||||
|
||||
@@ -953,7 +1018,7 @@ void exec( job_t *j )
|
||||
false during builtin execution so as not to confuse
|
||||
some job-handling builtins.
|
||||
*/
|
||||
j->fg = fg;
|
||||
job_set_flag( j, JOB_FOREGROUND, fg );
|
||||
}
|
||||
|
||||
if( close_stdin )
|
||||
@@ -989,7 +1054,7 @@ void exec( job_t *j )
|
||||
*/
|
||||
if( p->next == 0 )
|
||||
{
|
||||
proc_set_last_status( j->negate?(status?0:1):status);
|
||||
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
|
||||
}
|
||||
p->completed = 1;
|
||||
break;
|
||||
@@ -1039,7 +1104,7 @@ void exec( job_t *j )
|
||||
{
|
||||
if( p->next == 0 )
|
||||
{
|
||||
proc_set_last_status( j->negate?(status?0:1):status);
|
||||
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
|
||||
}
|
||||
p->completed = 1;
|
||||
}
|
||||
@@ -1130,7 +1195,7 @@ void exec( job_t *j )
|
||||
{
|
||||
debug( 3, L"Set status of %ls to %d using short circut", j->command, p->status );
|
||||
|
||||
proc_set_last_status( j->negate?(p->status?0:1):p->status );
|
||||
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!p->status):p->status );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1190,7 +1255,7 @@ void exec( job_t *j )
|
||||
p->pid = getpid();
|
||||
setup_child_process( j, p );
|
||||
launch_process( p );
|
||||
|
||||
|
||||
/*
|
||||
launch_process _never_ returns...
|
||||
*/
|
||||
@@ -1246,6 +1311,15 @@ void exec( job_t *j )
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The keepalive process is no longer needed, so we terminate it
|
||||
with extreme prejudice
|
||||
*/
|
||||
if( needs_keepalive )
|
||||
{
|
||||
kill( keepalive.pid, SIGKILL );
|
||||
}
|
||||
|
||||
signal_unblock();
|
||||
|
||||
debug( 3, L"Job is constructed" );
|
||||
@@ -1255,9 +1329,9 @@ void exec( job_t *j )
|
||||
for( tmp = block_io; tmp; tmp=tmp->next )
|
||||
j->io = io_remove( j->io, tmp );
|
||||
|
||||
j->constructed = 1;
|
||||
job_set_flag( j, JOB_CONSTRUCTED, 1 );
|
||||
|
||||
if( !j->fg )
|
||||
if( !job_get_flag( j, JOB_FOREGROUND ) )
|
||||
{
|
||||
proc_last_bg_pid = j->pgid;
|
||||
}
|
||||
@@ -1283,7 +1357,7 @@ int exec_subshell( const wchar_t *cmd,
|
||||
debug( 1,
|
||||
_( L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %s." ),
|
||||
PACKAGE_BUGREPORT );
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
is_subshell=1;
|
||||
@@ -1291,11 +1365,17 @@ int exec_subshell( const wchar_t *cmd,
|
||||
|
||||
prev_status = proc_get_last_status();
|
||||
|
||||
eval( cmd, io_buffer, SUBST );
|
||||
if( eval( cmd, io_buffer, SUBST ) )
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = proc_get_last_status();
|
||||
}
|
||||
|
||||
io_buffer_read( io_buffer );
|
||||
|
||||
status = proc_get_last_status();
|
||||
proc_set_last_status( prev_status );
|
||||
|
||||
is_subshell = prev_subshell;
|
||||
|
||||
4
exec.h
4
exec.h
@@ -51,8 +51,8 @@ void exec( job_t *j );
|
||||
|
||||
\return the status of the last job to exit, or -1 if en error was encountered.
|
||||
*/
|
||||
int exec_subshell( const wchar_t *cmd,
|
||||
array_list_t *l );
|
||||
__warn_unused int exec_subshell( const wchar_t *cmd,
|
||||
array_list_t *l );
|
||||
|
||||
|
||||
/**
|
||||
|
||||
199
expand.c
199
expand.c
@@ -44,6 +44,7 @@ parameter expansion.
|
||||
#include "complete.h"
|
||||
|
||||
#include "parse_util.h"
|
||||
#include "halloc.h"
|
||||
#include "halloc_util.h"
|
||||
|
||||
/**
|
||||
@@ -654,8 +655,8 @@ static int expand_pid( wchar_t *in,
|
||||
free( in );
|
||||
else
|
||||
{
|
||||
*in = L'%';
|
||||
al_push( out, in );
|
||||
free(in);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -743,6 +744,55 @@ void expand_variable_error( const wchar_t *token, int token_pos, int error_pos )
|
||||
}
|
||||
|
||||
|
||||
static int parse_slice( wchar_t *in, wchar_t **end_ptr, array_list_t *idx )
|
||||
{
|
||||
|
||||
|
||||
wchar_t *end;
|
||||
|
||||
int pos = 1;
|
||||
|
||||
// debug( 0, L"parse_slice on '%ls'", in );
|
||||
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
long tmp;
|
||||
|
||||
while( iswspace(in[pos]) || (in[pos]==INTERNAL_SEPARATOR))
|
||||
pos++;
|
||||
|
||||
if( in[pos] == L']' )
|
||||
{
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
errno=0;
|
||||
tmp = wcstol( &in[pos], &end, 10 );
|
||||
if( ( errno ) || ( end == &in[pos] ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
// debug( 0, L"Push idx %d", tmp );
|
||||
|
||||
al_push_long( idx, tmp );
|
||||
pos = end-in;
|
||||
}
|
||||
|
||||
if( end_ptr )
|
||||
{
|
||||
// debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos );
|
||||
|
||||
*end_ptr = in+pos;
|
||||
}
|
||||
// debug( 0, L"ok, done" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Expand all environment variables in the string *ptr.
|
||||
|
||||
@@ -841,44 +891,22 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
|
||||
int all_vars=1;
|
||||
array_list_t var_item_list;
|
||||
al_init( &var_item_list );
|
||||
|
||||
|
||||
if( in[stop_pos] == L'[' )
|
||||
{
|
||||
wchar_t *end;
|
||||
|
||||
all_vars = 0;
|
||||
|
||||
stop_pos++;
|
||||
while( 1 )
|
||||
wchar_t *slice_end;
|
||||
all_vars=0;
|
||||
|
||||
if( parse_slice( &in[stop_pos], &slice_end, var_idx_list ) )
|
||||
{
|
||||
long tmp;
|
||||
|
||||
while( iswspace(in[stop_pos]) || (in[stop_pos]==INTERNAL_SEPARATOR))
|
||||
stop_pos++;
|
||||
|
||||
|
||||
if( in[stop_pos] == L']' )
|
||||
{
|
||||
stop_pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
errno=0;
|
||||
tmp = wcstol( &in[stop_pos], &end, 10 );
|
||||
if( ( errno ) || ( end == &in[stop_pos] ) )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
-1,
|
||||
L"Expected integer or \']\'" );
|
||||
|
||||
is_ok = 0;
|
||||
break;
|
||||
}
|
||||
al_push_long( var_idx_list, tmp );
|
||||
stop_pos = end-in;
|
||||
}
|
||||
}
|
||||
|
||||
error( SYNTAX_ERROR,
|
||||
-1,
|
||||
L"Invalid index value" );
|
||||
is_ok = 0;
|
||||
}
|
||||
stop_pos = (slice_end-in);
|
||||
}
|
||||
|
||||
if( is_ok )
|
||||
{
|
||||
tokenize_variable_array( var_val, &var_item_list );
|
||||
@@ -1189,16 +1217,20 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
|
||||
static int expand_cmdsubst( wchar_t *in, array_list_t *out )
|
||||
{
|
||||
wchar_t *paran_begin=0, *paran_end=0;
|
||||
int len1, len2;
|
||||
int len1;
|
||||
wchar_t prev=0;
|
||||
wchar_t *subcmd;
|
||||
array_list_t sub_res, tail_expand;
|
||||
array_list_t *sub_res, *tail_expand;
|
||||
int i, j;
|
||||
const wchar_t *item_begin;
|
||||
wchar_t *tail_begin = 0;
|
||||
void *context;
|
||||
|
||||
CHECK( in, 0 );
|
||||
CHECK( out, 0 );
|
||||
|
||||
|
||||
|
||||
switch( parse_util_locate_cmdsubst(in,
|
||||
¶n_begin,
|
||||
¶n_end,
|
||||
@@ -1217,38 +1249,97 @@ static int expand_cmdsubst( wchar_t *in, array_list_t *out )
|
||||
break;
|
||||
}
|
||||
|
||||
context = halloc( 0, 0 );
|
||||
|
||||
len1 = (paran_begin-in);
|
||||
len2 = wcslen(paran_end)-1;
|
||||
prev=0;
|
||||
item_begin = paran_begin+1;
|
||||
|
||||
al_init( &sub_res );
|
||||
if( !(subcmd = malloc( sizeof(wchar_t)*(paran_end-paran_begin) )))
|
||||
sub_res = al_halloc( context );
|
||||
if( !(subcmd = halloc( context, sizeof(wchar_t)*(paran_end-paran_begin) )))
|
||||
{
|
||||
al_destroy( &sub_res );
|
||||
halloc_free( context );
|
||||
return 0;
|
||||
}
|
||||
|
||||
wcslcpy( subcmd, paran_begin+1, paran_end-paran_begin );
|
||||
subcmd[ paran_end-paran_begin-1]=0;
|
||||
|
||||
exec_subshell( subcmd, &sub_res);
|
||||
if( exec_subshell( subcmd, sub_res) == -1 )
|
||||
{
|
||||
halloc_free( context );
|
||||
error( CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
al_init( &tail_expand );
|
||||
expand_cmdsubst( wcsdup(paran_end+1), &tail_expand );
|
||||
tail_begin = paran_end + 1;
|
||||
if( *tail_begin == L'[' )
|
||||
{
|
||||
array_list_t *slice_idx = al_halloc( context );
|
||||
wchar_t *slice_end;
|
||||
|
||||
if( parse_slice( tail_begin, &slice_end, slice_idx ) )
|
||||
{
|
||||
halloc_free( context );
|
||||
error( SYNTAX_ERROR, -1, L"Invalid index value" );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_list_t *sub_res2 = al_halloc( context );
|
||||
tail_begin = slice_end;
|
||||
for( i=0; i<al_get_count( slice_idx ); i++ )
|
||||
{
|
||||
long idx = al_get_long( slice_idx, i );
|
||||
if( idx < 0 )
|
||||
{
|
||||
idx = al_get_count( sub_res ) + idx + 1;
|
||||
}
|
||||
|
||||
if( idx < 1 || idx > al_get_count( sub_res ) )
|
||||
{
|
||||
halloc_free( context );
|
||||
error( SYNTAX_ERROR, -1, L"Invalid index value" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx = idx-1;
|
||||
|
||||
al_push( sub_res2, al_get( sub_res, idx ) );
|
||||
// debug( 0, L"Pushing item '%ls' with index %d onto sliced result", al_get( sub_res, idx ), idx );
|
||||
|
||||
al_set( sub_res, idx, 0 );
|
||||
}
|
||||
al_foreach( sub_res, &free );
|
||||
sub_res = sub_res2;
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<al_get_count( &sub_res ); i++ )
|
||||
tail_expand = al_halloc( context );
|
||||
|
||||
/*
|
||||
Recursively call ourselves to expand any remaining command
|
||||
substitutions. The result of this recursive call usiung the tail
|
||||
of the string is inserted into the tail_expand array list
|
||||
*/
|
||||
expand_cmdsubst( wcsdup(tail_begin), tail_expand );
|
||||
|
||||
/*
|
||||
Combine the result of the current command substitution with the
|
||||
result of the recursive tail expansion
|
||||
*/
|
||||
for( i=0; i<al_get_count( sub_res ); i++ )
|
||||
{
|
||||
wchar_t *sub_item, *sub_item2;
|
||||
sub_item = (wchar_t *)al_get( &sub_res, i );
|
||||
sub_item = (wchar_t *)al_get( sub_res, i );
|
||||
sub_item2 = escape( sub_item, 1 );
|
||||
free(sub_item);
|
||||
int item_len = wcslen( sub_item2 );
|
||||
|
||||
for( j=0; j<al_get_count( &tail_expand ); j++ )
|
||||
for( j=0; j<al_get_count( tail_expand ); j++ )
|
||||
{
|
||||
string_buffer_t whole_item;
|
||||
wchar_t *tail_item = (wchar_t *)al_get( &tail_expand, j );
|
||||
wchar_t *tail_item = (wchar_t *)al_get( tail_expand, j );
|
||||
|
||||
sb_init( &whole_item );
|
||||
|
||||
@@ -1265,12 +1356,8 @@ static int expand_cmdsubst( wchar_t *in, array_list_t *out )
|
||||
}
|
||||
free(in);
|
||||
|
||||
al_destroy( &sub_res );
|
||||
|
||||
al_foreach( &tail_expand, &free );
|
||||
al_destroy( &tail_expand );
|
||||
|
||||
free( subcmd );
|
||||
al_foreach( tail_expand, &free );
|
||||
halloc_free( context );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
2
expand.h
2
expand.h
@@ -139,7 +139,7 @@ enum
|
||||
\param out The list to which the result will be appended.
|
||||
\return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH. EXPAND_WILDCARD_NO_MATCH and EXPAND_WILDCARD_MATCH are normal exit conditions used only on strings containing wildcards to tell if the wildcard produced any matches.
|
||||
*/
|
||||
int expand_string( void *context, wchar_t *in, array_list_t *out, int flag );
|
||||
__warn_unused int expand_string( void *context, wchar_t *in, array_list_t *out, int flag );
|
||||
|
||||
/**
|
||||
expand_one is identical to expand_string, except it will fail if in
|
||||
|
||||
17
fallback.c
17
fallback.c
@@ -1072,7 +1072,22 @@ int _nl_msg_cat_cntr=0;
|
||||
#ifndef HAVE_KILLPG
|
||||
int killpg( int pgr, int sig )
|
||||
{
|
||||
assert( pgr > 0 );
|
||||
assert( pgr > 1 );
|
||||
return kill( -pgr, sig );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_WORKING_GETOPT_LONG
|
||||
|
||||
int getopt_long( int argc,
|
||||
char * const argv[],
|
||||
const char *optstring,
|
||||
const struct option *longopts,
|
||||
int *longindex )
|
||||
{
|
||||
return getopt( argc, argv, optstring );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
40
fallback.h
40
fallback.h
@@ -9,6 +9,8 @@
|
||||
#include <wchar.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef WCHAR_MAX
|
||||
/**
|
||||
@@ -47,6 +49,10 @@ typedef char tputs_arg_t;
|
||||
#define SIGIO SIGUSR1
|
||||
#endif
|
||||
|
||||
#ifndef SIGWINCH
|
||||
#define SIGWINCH SIGUSR2
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_WINSIZE
|
||||
struct winsize
|
||||
{
|
||||
@@ -304,7 +310,7 @@ size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
|
||||
/**
|
||||
BSD del_curterm seems to do a double-free. We redefine it as a no-op
|
||||
*/
|
||||
#define del_curterm(oterm) 1
|
||||
#define del_curterm(oterm) OK
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_LRAND48_R
|
||||
@@ -385,5 +391,37 @@ extern int _nl_msg_cat_cntr;
|
||||
int killpg( int pgr, int sig );
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_WORKING_GETOPT_LONG
|
||||
|
||||
struct option
|
||||
{
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
}
|
||||
;
|
||||
|
||||
#ifndef no_argument
|
||||
#define no_argument 0
|
||||
#endif
|
||||
|
||||
#ifndef required_argument
|
||||
#define required_argument 1
|
||||
#endif
|
||||
|
||||
#ifndef optional_argument
|
||||
#define optional_argument 2
|
||||
#endif
|
||||
|
||||
int getopt_long(int argc,
|
||||
char * const argv[],
|
||||
const char *optstring,
|
||||
const struct option *longopts,
|
||||
int *longindex);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
17
fish.spec.in
17
fish.spec.in
@@ -6,9 +6,9 @@ Release: 0%{?dist}
|
||||
|
||||
License: GPL
|
||||
Group: System Environment/Shells
|
||||
URL: http://roo.no-ip.org/fish/
|
||||
URL: http://www.fishshell.org
|
||||
|
||||
Source0: http://roo.no-ip.org/%{name}/files/%{version}/%{name}-%{version}.tar.bz2
|
||||
Source0: http://www.fishshell.org/files/%{version}/%{name}-%{version}.tar.bz2
|
||||
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: ncurses-devel gettext groff
|
||||
@@ -133,14 +133,14 @@ fi
|
||||
%attr(0755,root,root) %_bindir/count
|
||||
|
||||
# Configuration files
|
||||
%config %_sysconfdir/fish
|
||||
%config %_sysconfdir/fish_inputrc
|
||||
%dir %_sysconfdir/fish.d
|
||||
%config %_sysconfdir/fish.d/fish_*.fish
|
||||
%config %_sysconfdir/fish/config.fish
|
||||
%config %_sysconfdir/fish/fish_inputrc
|
||||
%dir %_sysconfdir/fish
|
||||
|
||||
# Non-configuration initialization files
|
||||
%dir %_datadir/fish
|
||||
%_datadir/fish/fish
|
||||
%_datadir/fish/config.fish
|
||||
%_datadir/fish/config_interactive.fish
|
||||
|
||||
# Program specific tab-completions
|
||||
%dir %_datadir/fish/completions
|
||||
@@ -155,6 +155,9 @@ fi
|
||||
|
||||
|
||||
%changelog
|
||||
* Sat Oct 14 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.22.0-0
|
||||
- Update names of various configuration files
|
||||
|
||||
* Fri Aug 4 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.21.10-4
|
||||
- Add better translation finding code from fedora spec to main spec. Thank you to Michael Schwendt.
|
||||
- Add missing dependency libXext-devel.
|
||||
|
||||
252
fish_pager.c
252
fish_pager.c
@@ -74,6 +74,33 @@ enum
|
||||
}
|
||||
;
|
||||
|
||||
enum
|
||||
{
|
||||
/*
|
||||
Returnd by the pager if no more displaying is needed
|
||||
*/
|
||||
PAGER_DONE,
|
||||
/*
|
||||
Returned by the pager if the completions would not fit in the specified number of columns
|
||||
*/
|
||||
PAGER_RETRY,
|
||||
/*
|
||||
Returned by the pager if the terminal changes size
|
||||
*/
|
||||
PAGER_RESIZE
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
The minimum number of columns the terminal may have for fish_pager to not refuse showing the completions
|
||||
*/
|
||||
#define PAGER_MIN_WIDTH 16
|
||||
|
||||
/**
|
||||
The maximum number of columns of completion to attempt to fit onto the screen
|
||||
*/
|
||||
#define PAGER_MAX_COLS 6
|
||||
|
||||
/**
|
||||
This struct should be continually updated by signals as the term
|
||||
resizes, and as such always contain the correct current size.
|
||||
@@ -81,11 +108,23 @@ enum
|
||||
|
||||
static struct winsize termsize;
|
||||
|
||||
/**
|
||||
The termios modes the terminal had when the program started. These
|
||||
should be restored on exit
|
||||
*/
|
||||
static struct termios saved_modes;
|
||||
static struct termios pager_modes;
|
||||
|
||||
/**
|
||||
This flag is set to 1 of we have sent the enter_ca_mode terminfo
|
||||
sequence to save the previous terminal contents.
|
||||
*/
|
||||
static int is_ca_mode = 0;
|
||||
|
||||
/**
|
||||
This buffer_t is used to buffer the output of the pager to improve
|
||||
screen redraw performance bu cutting down the number of write()
|
||||
calls to only one.
|
||||
*/
|
||||
static buffer_t *pager_buffer;
|
||||
|
||||
/**
|
||||
@@ -101,7 +140,13 @@ static wchar_t *hightlight_var[] =
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
This string_buffer_t contains the text that should be sent back to the calling program
|
||||
*/
|
||||
static string_buffer_t out_buff;
|
||||
/**
|
||||
This is the file to which the output text should be sent. It is really a pipe.
|
||||
*/
|
||||
static FILE *out_file;
|
||||
|
||||
/**
|
||||
@@ -136,6 +181,10 @@ typedef struct
|
||||
}
|
||||
comp_t;
|
||||
|
||||
/**
|
||||
This function translates from a highlight code to a specific color
|
||||
by check invironement variables
|
||||
*/
|
||||
static int get_color( int highlight )
|
||||
{
|
||||
wchar_t *val;
|
||||
@@ -160,6 +209,12 @@ static int get_color( int highlight )
|
||||
return output_color_code( val );
|
||||
}
|
||||
|
||||
/**
|
||||
This function calculates the minimum width for each completion
|
||||
entry in the specified array_list. This width depends on the
|
||||
terminal size, so this function should be called when the terminal
|
||||
changes size.
|
||||
*/
|
||||
static void recalc_width( array_list_t *l, const wchar_t *prefix )
|
||||
{
|
||||
int i;
|
||||
@@ -173,6 +228,10 @@ static void recalc_width( array_list_t *l, const wchar_t *prefix )
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Test if the specified character sequence has been entered on the
|
||||
keyboard
|
||||
*/
|
||||
static int try_sequence( char *seq )
|
||||
{
|
||||
int j, k;
|
||||
@@ -196,6 +255,9 @@ static int try_sequence( char *seq )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Read a character from keyboard
|
||||
*/
|
||||
static wint_t readch()
|
||||
{
|
||||
struct mapping
|
||||
@@ -255,26 +317,39 @@ static wint_t readch()
|
||||
return input_common_readch(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write specified character to the output buffer \c pager_buffer
|
||||
*/
|
||||
static int pager_buffered_writer( char c)
|
||||
{
|
||||
b_append( pager_buffer, &c, 1 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Flush \c pager_buffer to stdout
|
||||
*/
|
||||
static void pager_flush()
|
||||
{
|
||||
write( 1, pager_buffer->buff, pager_buffer->used );
|
||||
pager_buffer->used = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Print the specified string, but use at most the specified amount of
|
||||
space. If the whole string can't be fitted, ellipsize it.
|
||||
|
||||
\param str the string to print
|
||||
\param max the maximum space that may be used for printing
|
||||
\param has_more if this flag is true, this is not the entire string, and the string should be ellisiszed even if the string fits but takes up the whole space.
|
||||
*/
|
||||
static int print_max( const wchar_t *str, int max, int has_more )
|
||||
{
|
||||
int i;
|
||||
int written = 0;
|
||||
for( i=0; str[i]; i++ )
|
||||
{
|
||||
|
||||
if( written + wcwidth(str[i]) > max )
|
||||
break;
|
||||
if( ( written + wcwidth(str[i]) == max) && (has_more || str[i+1]) )
|
||||
@@ -290,6 +365,9 @@ static int print_max( const wchar_t *str, int max, int has_more )
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
Print the specified item using at the specified amount of space
|
||||
*/
|
||||
static void completion_print_item( const wchar_t *prefix, comp_t *c, int width )
|
||||
{
|
||||
int comp_width=0, desc_width=0;
|
||||
@@ -423,7 +501,7 @@ static void completion_print( int cols,
|
||||
\param is_quoted whether the completions should be quoted
|
||||
\param l the list of completions
|
||||
|
||||
\return zero if the specified number of columns do not fit, no-zero otherwise
|
||||
\return one of PAGER_RETRY, PAGER_DONE and PAGER_RESIZE
|
||||
*/
|
||||
|
||||
static int completion_try_print( int cols,
|
||||
@@ -434,11 +512,11 @@ static int completion_try_print( int cols,
|
||||
/*
|
||||
The calculated preferred width of each column
|
||||
*/
|
||||
int pref_width[32];
|
||||
int pref_width[PAGER_MAX_COLS];
|
||||
/*
|
||||
The calculated minimum width of each column
|
||||
*/
|
||||
int min_width[32];
|
||||
int min_width[PAGER_MAX_COLS];
|
||||
/*
|
||||
If the list can be printed with this width, width will contain the width of each column
|
||||
*/
|
||||
@@ -454,13 +532,13 @@ static int completion_try_print( int cols,
|
||||
|
||||
int pref_tot_width=0;
|
||||
int min_tot_width = 0;
|
||||
int res=0;
|
||||
int res=PAGER_RETRY;
|
||||
/*
|
||||
Skip completions on tiny terminals
|
||||
*/
|
||||
|
||||
if( termsize.ws_col < 16 )
|
||||
return 1;
|
||||
if( termsize.ws_col < PAGER_MIN_WIDTH )
|
||||
return PAGER_DONE;
|
||||
|
||||
memset( pref_width, 0, sizeof(pref_width) );
|
||||
memset( min_width, 0, sizeof(min_width) );
|
||||
@@ -545,11 +623,9 @@ static int completion_try_print( int cols,
|
||||
}
|
||||
}
|
||||
|
||||
// return cols==1;
|
||||
|
||||
if( print )
|
||||
{
|
||||
res=1;
|
||||
res=PAGER_DONE;
|
||||
if( rows < termsize.ws_row )
|
||||
{
|
||||
/* List fits on screen. Print it and leave */
|
||||
@@ -583,15 +659,19 @@ static int completion_try_print( int cols,
|
||||
*/
|
||||
while(do_loop)
|
||||
{
|
||||
wchar_t msg[10];
|
||||
int percent = 100*pos/(rows-termsize.ws_row+1);
|
||||
string_buffer_t msg;
|
||||
sb_init( &msg );
|
||||
|
||||
set_color( FISH_COLOR_BLACK,
|
||||
get_color(HIGHLIGHT_PAGER_PROGRESS) );
|
||||
swprintf( msg, 12,
|
||||
L" %ls(%d%%) \r",
|
||||
percent==100?L"":(percent >=10?L" ": L" "),
|
||||
percent );
|
||||
writestr(msg);
|
||||
sb_printf( &msg,
|
||||
_(L" %d to %d of %d \r"),
|
||||
pos,
|
||||
pos+termsize.ws_row-1,
|
||||
rows );
|
||||
|
||||
writestr((wchar_t *)msg.buff);
|
||||
sb_destroy( &msg );
|
||||
set_color( FISH_COLOR_NORMAL, FISH_COLOR_NORMAL );
|
||||
pager_flush();
|
||||
int c = readch();
|
||||
@@ -689,7 +769,7 @@ static int completion_try_print( int cols,
|
||||
case R_NULL:
|
||||
{
|
||||
do_loop=0;
|
||||
res=2;
|
||||
res=PAGER_RESIZE;
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -878,15 +958,28 @@ static void handle_winch( int sig )
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The callback function that the keyboard reading function calls when
|
||||
an interrupt occurs. This makes sure that R_NULL is returned at
|
||||
once when an interrupt has occured.
|
||||
*/
|
||||
static int interrupt_handler()
|
||||
{
|
||||
return R_NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize various subsystems. This also closes stdin and replaces
|
||||
it with a copy of stderr, so the reading of completion strings must
|
||||
be done before init is called.
|
||||
*/
|
||||
static void init()
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
static struct termios pager_modes;
|
||||
|
||||
|
||||
program_name = L"fish_pager";
|
||||
wsetlocale( LC_ALL, L"" );
|
||||
|
||||
@@ -903,21 +996,21 @@ static void init()
|
||||
{
|
||||
if( dup2( 2, 1 ) == -1 )
|
||||
{
|
||||
debug( 0, L"Could not set up output file descriptors for pager" );
|
||||
debug( 0, _(L"Could not set up output file descriptors for pager") );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if( dup2( in, 0 ) == -1 )
|
||||
{
|
||||
debug( 0, L"Could not set up input file descriptors for pager %d", in );
|
||||
debug( 0, _(L"Could not set up input file descriptors for pager %d"), in );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug( 0, L"Could not open tty for pager" );
|
||||
{
|
||||
debug( 0, _(L"Could not open tty for pager") );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
out_file = fdopen( out, "w" );
|
||||
|
||||
/**
|
||||
@@ -925,13 +1018,12 @@ static void init()
|
||||
*/
|
||||
sb_init( &out_buff );
|
||||
|
||||
halloc_util_init();
|
||||
env_universal_init( 0, 0, 0, 0);
|
||||
input_common_init( &interrupt_handler );
|
||||
output_set_writer( &pager_buffered_writer );
|
||||
pager_buffer = halloc( global_context, sizeof( buffer_t ) );
|
||||
halloc_register_function( global_context, (void (*)(void *))&b_destroy, pager_buffer );
|
||||
|
||||
|
||||
sigemptyset( & act.sa_mask );
|
||||
act.sa_flags=0;
|
||||
act.sa_handler=SIG_DFL;
|
||||
@@ -944,7 +1036,7 @@ static void init()
|
||||
}
|
||||
|
||||
handle_winch( 0 ); /* Set handler for window change events */
|
||||
|
||||
|
||||
tcgetattr(0,&pager_modes); /* get the current terminal modes */
|
||||
memcpy( &saved_modes,
|
||||
&pager_modes,
|
||||
@@ -966,17 +1058,21 @@ static void init()
|
||||
|
||||
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
|
||||
{
|
||||
debug( 0, L"Could not set up terminal" );
|
||||
debug( 0, _(L"Could not set up terminal") );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void destroy()
|
||||
/**
|
||||
Free memory used by various subsystems.
|
||||
*/
|
||||
static void destroy()
|
||||
{
|
||||
env_universal_destroy();
|
||||
input_common_destroy();
|
||||
halloc_util_destroy();
|
||||
wutil_destroy();
|
||||
if( del_curterm( cur_term ) == ERR )
|
||||
{
|
||||
debug( 0, _(L"Error while closing terminfo") );
|
||||
@@ -986,43 +1082,58 @@ void destroy()
|
||||
fclose( out_file );
|
||||
}
|
||||
|
||||
#define BUFSIZE 1024
|
||||
void read_array( FILE* file, array_list_t *comp )
|
||||
/**
|
||||
Read lines of input from the specified file, unescape them and
|
||||
insert them into the specified list.
|
||||
*/
|
||||
static void read_array( FILE* file, array_list_t *comp )
|
||||
{
|
||||
char buffer[BUFSIZE];
|
||||
buffer_t buffer;
|
||||
int c;
|
||||
int i;
|
||||
char cc;
|
||||
wchar_t *wcs, *unescaped;
|
||||
|
||||
b_init( &buffer );
|
||||
|
||||
while( !feof( file ) )
|
||||
{
|
||||
i = 0;
|
||||
while( i < BUFSIZE-1 )
|
||||
buffer.used=0;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
c = getc( file );
|
||||
if( c == EOF )
|
||||
{
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if( c == '\n' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cc=c;
|
||||
|
||||
buffer[ i++ ] = c;
|
||||
b_append( &buffer, &cc, 1 );
|
||||
}
|
||||
|
||||
buffer[ i ] = '\0';
|
||||
|
||||
wcs = str2wcs( buffer );
|
||||
if( wcs )
|
||||
if( buffer.used )
|
||||
{
|
||||
unescaped = unescape( wcs, 0 );
|
||||
al_push( comp, unescaped );
|
||||
free( wcs );
|
||||
cc=0;
|
||||
b_append( &buffer, &cc, 1 );
|
||||
|
||||
wcs = str2wcs( buffer.buff );
|
||||
if( wcs )
|
||||
{
|
||||
unescaped = unescape( wcs, 0 );
|
||||
al_push( comp, unescaped );
|
||||
free( wcs );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b_destroy( &buffer );
|
||||
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
@@ -1031,19 +1142,26 @@ int main( int argc, char **argv )
|
||||
int is_quoted=0;
|
||||
array_list_t *comp;
|
||||
wchar_t *prefix;
|
||||
|
||||
|
||||
/*
|
||||
This initialization is made early, so that the other init code
|
||||
can use global_context for memory managment
|
||||
*/
|
||||
halloc_util_init();
|
||||
|
||||
if( argc < 3 )
|
||||
{
|
||||
debug( 0, L"Insufficient arguments" );
|
||||
debug( 0, _(L"Insufficient arguments") );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
comp = al_halloc( global_context );
|
||||
prefix = str2wcs( argv[2] );
|
||||
is_quoted = strcmp( "1", argv[1] )==0;
|
||||
is_quoted = 0;
|
||||
|
||||
debug( 3, L"prefix is '%ls'", prefix );
|
||||
// debug( 3, L"prefix is '%ls'", prefix );
|
||||
|
||||
if( argc > 3 )
|
||||
{
|
||||
@@ -1061,28 +1179,44 @@ int main( int argc, char **argv )
|
||||
read_array( stdin, comp );
|
||||
}
|
||||
|
||||
|
||||
init();
|
||||
|
||||
mangle_descriptions( comp );
|
||||
|
||||
if( wcscmp( prefix, L"-" ) == 0 )
|
||||
join_completions( comp );
|
||||
join_completions( comp );
|
||||
|
||||
mangle_completions( comp, prefix );
|
||||
|
||||
for( i = 6; i>0; i-- )
|
||||
|
||||
/**
|
||||
Try to print the completions. Start by trying to print the
|
||||
list in PAGER_MAX_COLS columns, if the completions won't
|
||||
fit, reduce the number of columns by one. Printing a single
|
||||
column never fails.
|
||||
*/
|
||||
for( i = PAGER_MAX_COLS; i>0; i-- )
|
||||
{
|
||||
switch( completion_try_print( i, prefix, is_quoted, comp ) )
|
||||
{
|
||||
case 0:
|
||||
|
||||
case PAGER_RETRY:
|
||||
break;
|
||||
case 1:
|
||||
|
||||
case PAGER_DONE:
|
||||
i=0;
|
||||
break;
|
||||
case 2:
|
||||
i=7;
|
||||
|
||||
case PAGER_RESIZE:
|
||||
/*
|
||||
This means we got a resize event, so we start
|
||||
over from the beginning. Since it the screen got
|
||||
bigger, we might be able to fit all completions
|
||||
on-screen.
|
||||
*/
|
||||
i=PAGER_MAX_COLS+1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
free(prefix );
|
||||
|
||||
52
fish_tests.c
52
fish_tests.c
@@ -88,14 +88,6 @@ static void err( wchar_t *blah, ... )
|
||||
wprintf( L"\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
Print ok message
|
||||
*/
|
||||
static void ok()
|
||||
{
|
||||
wprintf( L"OK\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
Compare two pointers
|
||||
*/
|
||||
@@ -120,7 +112,7 @@ static void pq_test( int elements )
|
||||
|
||||
for( i=0; i<elements; i++ )
|
||||
{
|
||||
int foo = rand() % 100;
|
||||
long foo = rand() % 100;
|
||||
// printf( "Adding %d\n", foo );
|
||||
pq_put( &q, (void *)foo );
|
||||
count[foo]++;
|
||||
@@ -130,7 +122,7 @@ static void pq_test( int elements )
|
||||
|
||||
for( i=0; i<elements; i++ )
|
||||
{
|
||||
int pos = (int)pq_get( &q );
|
||||
long pos = (long)pq_get( &q );
|
||||
count[ pos ]--;
|
||||
if( pos > prev )
|
||||
err( L"Wrong order of elements in priority_queue_t" );
|
||||
@@ -201,7 +193,7 @@ static int hash_func( void *data )
|
||||
/* srand( (int)data );
|
||||
return rand();
|
||||
*/
|
||||
int foo = (int)data;
|
||||
int foo = (int)(long)data;
|
||||
return 127*((foo^0xefc7e214)) ^(foo<<11);
|
||||
}
|
||||
|
||||
@@ -217,9 +209,9 @@ static int compare_func( void *key1, void *key2 )
|
||||
/**
|
||||
Hashtable test
|
||||
*/
|
||||
static int hash_test( int elements )
|
||||
static int hash_test( long elements )
|
||||
{
|
||||
int i;
|
||||
long i;
|
||||
int res=1;
|
||||
|
||||
hash_table_t h;
|
||||
@@ -228,17 +220,17 @@ static int hash_test( int elements )
|
||||
|
||||
for( i=1; i< elements+1; i++ )
|
||||
{
|
||||
hash_put( &h, (void*)i, (void*)100-i );
|
||||
hash_put( &h, (void*)i, (void*)100l-i );
|
||||
}
|
||||
|
||||
for( i=1; i< elements+1; i++ )
|
||||
{
|
||||
if( (int)hash_get( &h, (void*)i ) != (100-i) )
|
||||
if( (long)hash_get( &h, (void*)i ) != (100l-i) )
|
||||
{
|
||||
err( L"Key %d gave data %d, expected data %d",
|
||||
i,
|
||||
(int)hash_get( &h, (void*)i ),
|
||||
100-i );
|
||||
(long)hash_get( &h, (void*)i ),
|
||||
100l-i );
|
||||
res = 0;
|
||||
|
||||
break;
|
||||
@@ -271,7 +263,7 @@ static int hash_test( int elements )
|
||||
|
||||
for( i=1; i<elements+1; i++ )
|
||||
{
|
||||
if( hash_contains( &h, (void*)i) != (i+1)%2 )
|
||||
if( hash_contains( &h, (void*)i) != (i+1l)%2l )
|
||||
{
|
||||
if( i%2 )
|
||||
err( L"Key %d remains, should be deleted",
|
||||
@@ -484,43 +476,43 @@ static void test_parser()
|
||||
|
||||
|
||||
say( L"Testing null input to parser" );
|
||||
if( !parser_test( 0, 0, 0 ) )
|
||||
if( !parser_test( 0, 0, 0, 0 ) )
|
||||
{
|
||||
err( L"Null input to parser_test undetected" );
|
||||
}
|
||||
|
||||
say( L"Testing block nesting" );
|
||||
if( !parser_test( L"if; end", 0, 0 ) )
|
||||
if( !parser_test( L"if; end", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"Incomplete if statement undetected" );
|
||||
}
|
||||
if( !parser_test( L"if test; echo", 0, 0 ) )
|
||||
if( !parser_test( L"if test; echo", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"Missing end undetected" );
|
||||
}
|
||||
if( !parser_test( L"if test; end; end", 0, 0 ) )
|
||||
if( !parser_test( L"if test; end; end", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"Unbalanced end undetected" );
|
||||
}
|
||||
|
||||
say( L"Testing detection of invalid use of builtin commands" );
|
||||
if( !parser_test( L"case foo", 0, 0 ) )
|
||||
if( !parser_test( L"case foo", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"'case' command outside of block context undetected" );
|
||||
}
|
||||
if( !parser_test( L"switch ggg; if true; case foo;end;end", 0, 0 ) )
|
||||
if( !parser_test( L"switch ggg; if true; case foo;end;end", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"'case' command outside of switch block context undetected" );
|
||||
}
|
||||
if( !parser_test( L"else", 0, 0 ) )
|
||||
if( !parser_test( L"else", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"'else' command outside of conditional block context undetected" );
|
||||
}
|
||||
if( !parser_test( L"break", 0, 0 ) )
|
||||
if( !parser_test( L"break", 0, 0, 0 ) )
|
||||
{
|
||||
err( L"'break' command outside of loop block context undetected" );
|
||||
}
|
||||
if( !parser_test( L"exec ls|less", 0, 0 ) || !parser_test( L"echo|return", 0, 0 ))
|
||||
if( !parser_test( L"exec ls|less", 0, 0, 0 ) || !parser_test( L"echo|return", 0, 0, 0 ))
|
||||
{
|
||||
err( L"Invalid pipe command undetected" );
|
||||
}
|
||||
@@ -553,7 +545,11 @@ static int expand_test( const wchar_t *in, int flags, ... )
|
||||
wchar_t *arg;
|
||||
|
||||
al_init( &out );
|
||||
expand_string( 0, wcsdup(in), &out, flags);
|
||||
if( expand_string( 0, wcsdup(in), &out, flags) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
va_start( va, flags );
|
||||
|
||||
|
||||
156
fishd.c
156
fishd.c
@@ -17,10 +17,12 @@ set_export KEY:VALUE
|
||||
|
||||
These commands update the value of a variable. The only difference
|
||||
between the two is that <tt>set_export</tt>-variables should be
|
||||
exported to children of the process using them. The variable value may
|
||||
be escaped using C-style backslash escapes. In fact, this is required
|
||||
for newline characters, which would otherwise be interpreted as end of
|
||||
command.
|
||||
exported to children of the process using them. When sending messages,
|
||||
all values below 32 or above 127 must be escaped using C-style
|
||||
backslash escapes. This means that the over the wire protocol is
|
||||
ASCII. However, any conforming reader must also accept non-ascii
|
||||
characters and interpret them as UTF-8. Lines containing invalid UTF-8
|
||||
escape sequences must be ignored entirely.
|
||||
|
||||
<pre>erase KEY
|
||||
</pre>
|
||||
@@ -68,6 +70,9 @@ time the original barrier request was sent have been received.
|
||||
#include "common.h"
|
||||
#include "wutil.h"
|
||||
#include "env_universal_common.h"
|
||||
#include "halloc.h"
|
||||
#include "halloc_util.h"
|
||||
#include "path.h"
|
||||
|
||||
/**
|
||||
Maximum length of socket filename
|
||||
@@ -98,7 +103,7 @@ time the original barrier request was sent have been received.
|
||||
/**
|
||||
The name of the save file. The hostname is appended to this.
|
||||
*/
|
||||
#define FILE ".fishd."
|
||||
#define FILE "fishd."
|
||||
|
||||
/**
|
||||
Maximum length of hostname. Longer hostnames are truncated
|
||||
@@ -386,23 +391,108 @@ static void daemonize()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Get environment variable value. The resulting string needs to be free'd.
|
||||
*/
|
||||
static wchar_t *fishd_env_get( wchar_t *key )
|
||||
{
|
||||
char *nres, *nkey;
|
||||
wchar_t *res;
|
||||
|
||||
nkey = wcs2str( key );
|
||||
nres = getenv( nkey );
|
||||
free( nkey );
|
||||
if( nres )
|
||||
{
|
||||
return str2wcs( nres );
|
||||
}
|
||||
else
|
||||
{
|
||||
res = env_universal_common_get( key );
|
||||
if( res )
|
||||
res = wcsdup( res );
|
||||
|
||||
return env_universal_common_get( key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the configuration directory. The resulting string needs to be
|
||||
free'd. This is mostly the same code as path_get_config(), but had
|
||||
to be rewritten to avoid dragging in additional library
|
||||
dependencies.
|
||||
*/
|
||||
static wchar_t *fishd_get_config()
|
||||
{
|
||||
wchar_t *xdg_dir, *home;
|
||||
int done = 0;
|
||||
wchar_t *res = 0;
|
||||
|
||||
xdg_dir = fishd_env_get( L"XDG_CONFIG_HOME" );
|
||||
if( xdg_dir )
|
||||
{
|
||||
res = wcsdupcat( xdg_dir, L"/fish" );
|
||||
if( !create_directory( res ) )
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
free( res );
|
||||
}
|
||||
free( xdg_dir );
|
||||
}
|
||||
else
|
||||
{
|
||||
home = fishd_env_get( L"HOME" );
|
||||
if( home )
|
||||
{
|
||||
res = wcsdupcat( home, L"/.config/fish" );
|
||||
if( !create_directory( res ) )
|
||||
{
|
||||
done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
free( res );
|
||||
}
|
||||
free( home );
|
||||
}
|
||||
}
|
||||
|
||||
if( done )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug( 0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access." ));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Load or save all variables
|
||||
*/
|
||||
void load_or_save( int save)
|
||||
static void load_or_save( int save)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *name;
|
||||
char *dir = getenv( "HOME" );
|
||||
wchar_t *wdir = fishd_get_config();
|
||||
char *dir;
|
||||
char hostname[HOSTNAME_LEN];
|
||||
connection_t c;
|
||||
int fd;
|
||||
|
||||
if( !dir )
|
||||
if( !wdir )
|
||||
{
|
||||
pw = getpwuid( getuid() );
|
||||
dir = pw->pw_dir;
|
||||
return;
|
||||
}
|
||||
|
||||
dir = wcs2str( wdir );
|
||||
|
||||
free( wdir );
|
||||
|
||||
gethostname( hostname, HOSTNAME_LEN );
|
||||
|
||||
name = malloc( strlen(dir)+ strlen(FILE)+ strlen(hostname) + 2 );
|
||||
@@ -410,15 +500,19 @@ void load_or_save( int save)
|
||||
strcat( name, "/" );
|
||||
strcat( name, FILE );
|
||||
strcat( name, hostname );
|
||||
|
||||
free( dir );
|
||||
|
||||
|
||||
debug( 4, L"Open file for %s: '%s'",
|
||||
save?"saving":"loading",
|
||||
name );
|
||||
|
||||
c.fd = open( name, save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
|
||||
fd = open( name, save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
|
||||
|
||||
free( name );
|
||||
|
||||
if( c.fd == -1 )
|
||||
if( fd == -1 )
|
||||
{
|
||||
debug( 1, L"Could not open load/save file. No previous saves?" );
|
||||
wperror( L"open" );
|
||||
@@ -426,9 +520,7 @@ void load_or_save( int save)
|
||||
}
|
||||
debug( 4, L"File open on fd %d", c.fd );
|
||||
|
||||
sb_init( &c.input );
|
||||
memset (&c.wstate, '\0', sizeof (mbstate_t));
|
||||
q_init( &c.unsent );
|
||||
connection_init( &c, fd );
|
||||
|
||||
if( save )
|
||||
{
|
||||
@@ -439,9 +531,7 @@ void load_or_save( int save)
|
||||
else
|
||||
read_message( &c );
|
||||
|
||||
q_destroy( &c.unsent );
|
||||
sb_destroy( &c.input );
|
||||
close( c.fd );
|
||||
connection_destroy( &c );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,6 +575,8 @@ int main( int argc, char ** argv )
|
||||
int update_count=0;
|
||||
|
||||
fd_set read_fd, write_fd;
|
||||
|
||||
halloc_util_init();
|
||||
|
||||
program_name=L"fishd";
|
||||
wsetlocale( LC_ALL, L"" );
|
||||
@@ -494,7 +586,6 @@ int main( int argc, char ** argv )
|
||||
*/
|
||||
while( 1 )
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static struct option
|
||||
long_options[] =
|
||||
{
|
||||
@@ -520,11 +611,6 @@ int main( int argc, char ** argv )
|
||||
long_options,
|
||||
&opt_index );
|
||||
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
@@ -553,7 +639,7 @@ int main( int argc, char ** argv )
|
||||
connection_t *c;
|
||||
int res;
|
||||
|
||||
t=sizeof( remote );
|
||||
t = sizeof( remote );
|
||||
|
||||
FD_ZERO( &read_fd );
|
||||
FD_ZERO( &write_fd );
|
||||
@@ -611,12 +697,8 @@ int main( int argc, char ** argv )
|
||||
else
|
||||
{
|
||||
connection_t *new = malloc( sizeof(connection_t));
|
||||
new->fd = child_socket;
|
||||
connection_init( new, child_socket );
|
||||
new->next = conn;
|
||||
q_init( &new->unsent );
|
||||
new->killme=0;
|
||||
sb_init( &new->input );
|
||||
memset (&new->wstate, '\0', sizeof (mbstate_t));
|
||||
send( new->fd, GREETING, strlen(GREETING), MSG_DONTWAIT );
|
||||
enqueue_all( new );
|
||||
conn=new;
|
||||
@@ -660,9 +742,6 @@ int main( int argc, char ** argv )
|
||||
{
|
||||
debug( 4, L"Close connection %d", c->fd );
|
||||
|
||||
close(c->fd );
|
||||
sb_destroy( &c->input );
|
||||
|
||||
while( !q_empty( &c->unsent ) )
|
||||
{
|
||||
message_t *msg = (message_t *)q_get( &c->unsent );
|
||||
@@ -671,7 +750,7 @@ int main( int argc, char ** argv )
|
||||
free( msg );
|
||||
}
|
||||
|
||||
q_destroy( &c->unsent );
|
||||
connection_destroy( c );
|
||||
if( prev )
|
||||
{
|
||||
prev->next=c->next;
|
||||
@@ -692,13 +771,16 @@ int main( int argc, char ** argv )
|
||||
c=c->next;
|
||||
}
|
||||
}
|
||||
|
||||
if( !conn )
|
||||
{
|
||||
debug( 0, L"No more clients. Quitting" );
|
||||
save();
|
||||
env_universal_common_destroy();
|
||||
exit(0);
|
||||
c=c->next;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
halloc_util_destroy();
|
||||
}
|
||||
|
||||
|
||||
18
function.c
18
function.c
@@ -44,10 +44,6 @@ typedef struct
|
||||
Line where definition started
|
||||
*/
|
||||
int definition_offset;
|
||||
/**
|
||||
Flag for specifying functions which are actually key bindings
|
||||
*/
|
||||
int is_binding;
|
||||
|
||||
/**
|
||||
Flag for specifying that this function was automatically loaded
|
||||
@@ -169,8 +165,7 @@ void function_destroy()
|
||||
void function_add( const wchar_t *name,
|
||||
const wchar_t *val,
|
||||
const wchar_t *desc,
|
||||
array_list_t *events,
|
||||
int is_binding )
|
||||
array_list_t *events )
|
||||
{
|
||||
int i;
|
||||
wchar_t *cmd_end;
|
||||
@@ -186,13 +181,8 @@ void function_add( const wchar_t *name,
|
||||
d->cmd = wcsdup( val );
|
||||
|
||||
cmd_end = d->cmd + wcslen(d->cmd)-1;
|
||||
while( (cmd_end>d->cmd) && wcschr( L"\n\r\t ", *cmd_end ) )
|
||||
{
|
||||
*cmd_end-- = 0;
|
||||
}
|
||||
|
||||
d->desc = desc?wcsdup( desc ):0;
|
||||
d->is_binding = is_binding;
|
||||
d->definition_file = intern(reader_current_filename());
|
||||
d->is_autoload = is_autoload;
|
||||
|
||||
@@ -319,9 +309,7 @@ static void get_names_internal( void *key,
|
||||
void *aux )
|
||||
{
|
||||
wchar_t *name = (wchar_t *)key;
|
||||
function_data_t *f = (function_data_t *)val;
|
||||
|
||||
if( name[0] != L'_' && !f->is_binding && !al_contains_str( (array_list_t *)aux, name ) )
|
||||
if( name[0] != L'_' && !al_contains_str( (array_list_t *)aux, name ) )
|
||||
{
|
||||
al_push( (array_list_t *)aux, name );
|
||||
}
|
||||
@@ -365,7 +353,6 @@ const wchar_t *function_get_definition_file( const wchar_t *argv )
|
||||
|
||||
CHECK( argv, 0 );
|
||||
|
||||
load( argv );
|
||||
data = (function_data_t *)hash_get( &function, argv );
|
||||
if( data == 0 )
|
||||
return 0;
|
||||
@@ -380,7 +367,6 @@ int function_get_definition_offset( const wchar_t *argv )
|
||||
|
||||
CHECK( argv, -1 );
|
||||
|
||||
load( argv );
|
||||
data = (function_data_t *)hash_get( &function, argv );
|
||||
if( data == 0 )
|
||||
return -1;
|
||||
|
||||
@@ -27,8 +27,7 @@ void function_destroy();
|
||||
void function_add( const wchar_t *name,
|
||||
const wchar_t *val,
|
||||
const wchar_t *desc,
|
||||
array_list_t *events,
|
||||
int is_binding );
|
||||
array_list_t *events );
|
||||
|
||||
/**
|
||||
Remove the function with the specified name.
|
||||
|
||||
60
halloc.c
60
halloc.c
@@ -24,9 +24,12 @@
|
||||
#define HALLOC_BLOCK_SIZE 128
|
||||
|
||||
/**
|
||||
Maximum size of trailing halloc space to refuse to discard
|
||||
Maximum size of trailing halloc space to refuse to discard. This is
|
||||
set to be larger on 64-bit platforms, since we don't want to get
|
||||
'stuck' with an unusably small slice of memory, and what is
|
||||
unusably small often depends on pointer size.
|
||||
*/
|
||||
#define HALLOC_SCRAP_SIZE 16
|
||||
#define HALLOC_SCRAP_SIZE (4*sizeof(void *))
|
||||
|
||||
#ifdef HALLOC_DEBUG
|
||||
/**
|
||||
@@ -71,24 +74,32 @@ typedef struct halloc
|
||||
/**
|
||||
Amount of free space in the scratch area
|
||||
*/
|
||||
size_t scratch_free;
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
/**
|
||||
The actual data. MAde to be of type long long to make sure memory alignment is in order.
|
||||
*/
|
||||
long long data[1]; // Waste one byte on non-C99 compilers... :-(
|
||||
#else
|
||||
long long data[];
|
||||
#endif
|
||||
ssize_t scratch_free;
|
||||
}
|
||||
halloc_t;
|
||||
|
||||
static void *align_ptr( void *in )
|
||||
{
|
||||
unsigned long step = maxi(sizeof(double),sizeof(void *));
|
||||
unsigned long inc = step-1;
|
||||
unsigned long long_in = (long)in;
|
||||
unsigned long long_out = ((long_in+inc)/step)*step;
|
||||
return (void *)long_out;
|
||||
}
|
||||
|
||||
static size_t align_sz( size_t in )
|
||||
{
|
||||
size_t step = maxi(sizeof(double),sizeof(void *));
|
||||
size_t inc = step-1;
|
||||
return ((in+inc)/step)*step;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the offset of the halloc structure before a data block
|
||||
*/
|
||||
static halloc_t *halloc_from_data( void *data )
|
||||
{
|
||||
return (halloc_t *)(((char *)data) - sizeof( halloc_t ) );
|
||||
return (halloc_t *)(((char *)data) - align_sz(sizeof( halloc_t ) ));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +115,7 @@ static void late_free( void *data)
|
||||
statistics, like number of allocations and number of internal calls
|
||||
to malloc.
|
||||
*/
|
||||
static void woot()
|
||||
static void halloc_report()
|
||||
{
|
||||
if( getpid() == pid )
|
||||
{
|
||||
@@ -115,25 +126,40 @@ static void woot()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void *halloc( void *context, size_t size )
|
||||
{
|
||||
halloc_t *me, *parent;
|
||||
if( context )
|
||||
{
|
||||
void *res;
|
||||
void *aligned;
|
||||
|
||||
#ifdef HALLOC_DEBUG
|
||||
|
||||
if( !child_count )
|
||||
{
|
||||
pid = getpid();
|
||||
atexit( woot );
|
||||
atexit( &halloc_report );
|
||||
}
|
||||
|
||||
child_count++;
|
||||
child_size += size;
|
||||
#endif
|
||||
parent = halloc_from_data( context );
|
||||
|
||||
/*
|
||||
Align memory address
|
||||
*/
|
||||
aligned = align_ptr( parent->scratch );
|
||||
|
||||
parent->scratch_free -= (aligned-parent->scratch);
|
||||
|
||||
if( parent->scratch_free < 0 )
|
||||
parent->scratch_free=0;
|
||||
|
||||
parent->scratch = aligned;
|
||||
|
||||
if( size <= parent->scratch_free )
|
||||
{
|
||||
res = parent->scratch;
|
||||
@@ -169,18 +195,18 @@ void *halloc( void *context, size_t size )
|
||||
}
|
||||
else
|
||||
{
|
||||
me = (halloc_t *)calloc( 1, sizeof(halloc_t) + size + HALLOC_BLOCK_SIZE );
|
||||
me = (halloc_t *)calloc( 1, align_sz(sizeof(halloc_t)) + align_sz(size) + HALLOC_BLOCK_SIZE );
|
||||
|
||||
if( !me )
|
||||
return 0;
|
||||
#ifdef HALLOC_DEBUG
|
||||
parent_count++;
|
||||
#endif
|
||||
me->scratch = ((char *)me) + sizeof(halloc_t) + size;
|
||||
me->scratch = ((char *)me) + align_sz(sizeof(halloc_t)) + align_sz(size);
|
||||
me->scratch_free = HALLOC_BLOCK_SIZE;
|
||||
|
||||
al_init( &me->children );
|
||||
return &me->data;
|
||||
return ((char *)me) + align_sz(sizeof(halloc_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
halloc.h
3
halloc.h
@@ -11,7 +11,8 @@
|
||||
|
||||
/**
|
||||
Allocate new memory using specified parent memory context. Context
|
||||
_must_ be either 0 or the result of a previous call to halloc.
|
||||
_must_ be either 0 or the result of a previous call to halloc. The
|
||||
resulting memory is set to zero.
|
||||
|
||||
If \c context is null, the resulting block is a root block, and
|
||||
must be freed with a call to halloc_free().
|
||||
|
||||
18
highlight.c
18
highlight.c
@@ -33,6 +33,7 @@
|
||||
#include "halloc.h"
|
||||
#include "halloc_util.h"
|
||||
#include "wildcard.h"
|
||||
#include "path.h"
|
||||
|
||||
/**
|
||||
Number of elements in the highlight_var array
|
||||
@@ -559,8 +560,7 @@ void highlight_shell( wchar_t * buff,
|
||||
{
|
||||
int last_type = tok_last_type( &tok );
|
||||
int prev_argc=0;
|
||||
|
||||
|
||||
|
||||
switch( last_type )
|
||||
{
|
||||
case TOK_STRING:
|
||||
@@ -589,7 +589,7 @@ void highlight_shell( wchar_t * buff,
|
||||
EXPAND_SKIP_CMDSUBST );
|
||||
if( dir )
|
||||
{
|
||||
if( !parser_cdpath_get( context, dir ) )
|
||||
if( !path_get_cdpath( context, dir ) )
|
||||
{
|
||||
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
|
||||
}
|
||||
@@ -624,7 +624,7 @@ void highlight_shell( wchar_t * buff,
|
||||
int is_subcommand = 0;
|
||||
int mark = tok_get_pos( &tok );
|
||||
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_COMMAND;
|
||||
|
||||
|
||||
if( parser_is_subcommand( cmd ) )
|
||||
{
|
||||
tok_next( &tok );
|
||||
@@ -672,13 +672,13 @@ void highlight_shell( wchar_t * buff,
|
||||
/*
|
||||
Check if this is a regular command
|
||||
*/
|
||||
is_cmd |= !!(tmp=parser_get_filename( context, cmd ));
|
||||
is_cmd |= !!(tmp=path_get_path( context, cmd ));
|
||||
|
||||
/*
|
||||
Could not find the command. Maybe it is
|
||||
a path for a implicit cd command.
|
||||
*/
|
||||
is_cmd |= !!(tmp=parser_cdpath_get( context, cmd ));
|
||||
is_cmd |= !!(tmp=path_get_cdpath( context, cmd ));
|
||||
|
||||
if( is_cmd )
|
||||
{
|
||||
@@ -687,7 +687,7 @@ void highlight_shell( wchar_t * buff,
|
||||
else
|
||||
{
|
||||
if( error )
|
||||
al_push( error, wcsdupcat2 ( L"Unknown command \'", cmd, L"\'", 0 ));
|
||||
al_push( error, wcsdupcat2 ( L"Unknown command \'", cmd, L"\'", (void *)0 ));
|
||||
color[ tok_get_pos( &tok ) ] = (HIGHLIGHT_ERROR);
|
||||
}
|
||||
had_cmd = 1;
|
||||
@@ -761,7 +761,7 @@ void highlight_shell( wchar_t * buff,
|
||||
{
|
||||
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
|
||||
if( error )
|
||||
al_push( error, wcsdupcat2( L"Directory \'", dir, L"\' does not exist", 0 ) );
|
||||
al_push( error, wcsdupcat2( L"Directory \'", dir, L"\' does not exist", (void *)0 ) );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -777,7 +777,7 @@ void highlight_shell( wchar_t * buff,
|
||||
{
|
||||
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
|
||||
if( error )
|
||||
al_push( error, wcsdupcat2( L"File \'", target, L"\' does not exist", 0 ) );
|
||||
al_push( error, wcsdupcat2( L"File \'", target, L"\' does not exist", (void *)0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ wchar_t *history_get( int idx );
|
||||
void history_first();
|
||||
|
||||
/**
|
||||
Make current point to last history item
|
||||
Make current point to last history item
|
||||
*/
|
||||
void history_reset();
|
||||
|
||||
@@ -61,7 +61,7 @@ const wchar_t *history_next_match( const wchar_t *str);
|
||||
of the history.
|
||||
*/
|
||||
|
||||
void history_set_mode( wchar_t *name );
|
||||
void history_set_mode( const wchar_t *name );
|
||||
|
||||
|
||||
/**
|
||||
|
||||
45
input.c
45
input.c
@@ -123,14 +123,17 @@ static const wchar_t *name_arr[] =
|
||||
L"kill-word",
|
||||
L"backward-kill-word",
|
||||
L"dump-functions",
|
||||
L"clear-screen",
|
||||
L"winch",
|
||||
L"exit",
|
||||
L"history-token-search-backward",
|
||||
L"history-token-search-forward",
|
||||
L"self-insert",
|
||||
L"null",
|
||||
L"eof",
|
||||
L"vi-arg-digit"
|
||||
L"vi-arg-digit",
|
||||
L"execute",
|
||||
L"beginning-of-buffer",
|
||||
L"end-of-buffer"
|
||||
}
|
||||
;
|
||||
|
||||
@@ -200,14 +203,17 @@ static const wchar_t code_arr[] =
|
||||
R_KILL_WORD,
|
||||
R_BACKWARD_KILL_WORD,
|
||||
R_DUMP_FUNCTIONS,
|
||||
R_CLEAR_SCREEN,
|
||||
R_WINCH,
|
||||
R_EXIT,
|
||||
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
||||
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
||||
R_SELF_INSERT,
|
||||
R_NULL,
|
||||
R_EOF,
|
||||
R_VI_ARG_DIGIT
|
||||
R_VI_ARG_DIGIT,
|
||||
R_EXECUTE,
|
||||
R_BEGINNING_OF_BUFFER,
|
||||
R_END_OF_BUFFER,
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1222,6 +1228,14 @@ static void add_common_bindings()
|
||||
*/
|
||||
for( i=0; i<3; i++ )
|
||||
{
|
||||
add_mapping( name[i], L"\n", L"Execute contents of commandline", L"execute" );
|
||||
|
||||
/*
|
||||
This will make Meta-newline insert a newline, since
|
||||
self-insert ignored the escape character unless it is the
|
||||
only character of the sequence.
|
||||
*/
|
||||
add_mapping( name[i], L"\e\n", L"Meta-newline", L"self-insert" );
|
||||
/*
|
||||
We need alternative keybidnings for arrowkeys, since
|
||||
terminfo sometimes specifies a different sequence than what
|
||||
@@ -1287,6 +1301,7 @@ static void add_common_bindings()
|
||||
add_escaped_mapping( name[i], (L"\\C-y"), L"Control-y", L"yank" );
|
||||
add_mapping( name[i], L"", L"Any key", L"self-insert" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1310,6 +1325,8 @@ static void add_emacs_bindings()
|
||||
add_escaped_mapping( L"emacs", (L"\ed"), L"Alt-d", L"forward-kill-word" );
|
||||
add_terminfo_mapping( L"emacs", (key_ppage), L"Page Up", L"beginning-of-history" );
|
||||
add_terminfo_mapping( L"emacs", (key_npage), L"Page Down", L"end-of-history" );
|
||||
add_escaped_mapping( L"emacs", (L"\e<"), L"Alt-<", L"beginning-of-buffer" );
|
||||
add_escaped_mapping( L"emacs", (L"\e>"), L"Alt->", L"end-of-buffer" );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1390,7 +1407,7 @@ static int interrupt_handler()
|
||||
/*
|
||||
Tell the reader an event occured
|
||||
*/
|
||||
if( reader_interupted() )
|
||||
if( reader_interrupted() )
|
||||
{
|
||||
/*
|
||||
Return 3, i.e. the character read by a Control-C.
|
||||
@@ -1398,7 +1415,7 @@ static int interrupt_handler()
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return R_WINCH;
|
||||
}
|
||||
|
||||
int input_init()
|
||||
@@ -1411,7 +1428,7 @@ int input_init()
|
||||
is_init = 1;
|
||||
|
||||
input_common_init( &interrupt_handler );
|
||||
|
||||
|
||||
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
|
||||
{
|
||||
debug( 0, _( L"Could not set up terminal" ) );
|
||||
@@ -1509,6 +1526,7 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq )
|
||||
{
|
||||
switch( code )
|
||||
{
|
||||
|
||||
case R_DUMP_FUNCTIONS:
|
||||
{
|
||||
for( i=0; i<repeat_count; i++ )
|
||||
@@ -1519,10 +1537,17 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq )
|
||||
|
||||
case R_SELF_INSERT:
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
if( seq[0] == L'\e' && seq[1] )
|
||||
{
|
||||
idx = 1;
|
||||
}
|
||||
|
||||
for( i=1; i<repeat_count; i++ )
|
||||
input_unreadch( seq[0] );
|
||||
input_unreadch( seq[idx] );
|
||||
repeat_count = 1;
|
||||
return seq[0];
|
||||
return seq[idx];
|
||||
}
|
||||
|
||||
case R_VI_ARG_DIGIT:
|
||||
@@ -1654,7 +1679,7 @@ wint_t input_readch()
|
||||
/*
|
||||
Clear the interrupted flag
|
||||
*/
|
||||
reader_interupted();
|
||||
reader_interrupted();
|
||||
|
||||
/*
|
||||
Search for sequence in various mapping tables
|
||||
|
||||
7
input.h
7
input.h
@@ -39,13 +39,16 @@ enum
|
||||
R_KILL_WORD,
|
||||
R_BACKWARD_KILL_WORD,
|
||||
R_DUMP_FUNCTIONS,
|
||||
R_CLEAR_SCREEN,
|
||||
R_WINCH,
|
||||
R_EXIT,
|
||||
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
||||
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
||||
R_SELF_INSERT,
|
||||
R_VI_ARG_DIGIT,
|
||||
R_VI_DELETE_TO
|
||||
R_VI_DELETE_TO,
|
||||
R_EXECUTE,
|
||||
R_BEGINNING_OF_BUFFER,
|
||||
R_END_OF_BUFFER
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ wchar_t input_common_readch( int timed )
|
||||
|
||||
int sz;
|
||||
|
||||
if( (b == R_NULL) || (b == R_EOF) )
|
||||
if( (b >= R_NULL) && (b < R_NULL + 1000) )
|
||||
return b;
|
||||
|
||||
bb=b;
|
||||
|
||||
143
kill.c
143
kill.c
@@ -29,8 +29,8 @@
|
||||
#include "common.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
#include "parser.h"
|
||||
#include "halloc.h"
|
||||
#include "path.h"
|
||||
|
||||
/**
|
||||
Maximum entries in killring
|
||||
@@ -50,7 +50,7 @@ static wchar_t *cut_buffer=0;
|
||||
static int has_xsel()
|
||||
{
|
||||
void *context = halloc(0, 0);
|
||||
wchar_t *path = parser_get_filename( context, L"xsel" );
|
||||
wchar_t *path = path_get_path( context, L"xsel" );
|
||||
int res = !!path;
|
||||
halloc_free( context );
|
||||
return res;
|
||||
@@ -96,8 +96,14 @@ void kill_add( wchar_t *str )
|
||||
if( (disp = env_get( L"DISPLAY" )) )
|
||||
{
|
||||
wchar_t *escaped_str = escape( str, 1 );
|
||||
wchar_t *cmd = wcsdupcat2(L"echo ", escaped_str, L"|xsel -b",0);
|
||||
exec_subshell( cmd, 0 );
|
||||
wchar_t *cmd = wcsdupcat2(L"echo ", escaped_str, L"|xsel -b",(void *)0);
|
||||
if( exec_subshell( cmd, 0 ) == -1 )
|
||||
{
|
||||
/*
|
||||
Do nothing on failiure
|
||||
*/
|
||||
}
|
||||
|
||||
free( cut_buffer );
|
||||
free( cmd );
|
||||
|
||||
@@ -105,6 +111,65 @@ void kill_add( wchar_t *str )
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Remove the specified node from the circular list
|
||||
*/
|
||||
static void kill_remove_node( ll_node_t *n )
|
||||
{
|
||||
if( n->prev == n )
|
||||
{
|
||||
kill_last=kill_current = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_node_t *nxt = n->prev;
|
||||
while( nxt->prev != n )
|
||||
{
|
||||
nxt=nxt->prev;
|
||||
}
|
||||
nxt->prev = n->prev;
|
||||
if( kill_last == n )
|
||||
{
|
||||
kill_last = n->prev;
|
||||
}
|
||||
kill_current=kill_last;
|
||||
free( n->data );
|
||||
free( n );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Remove first match for specified string from circular list
|
||||
*/
|
||||
static void kill_remove( wchar_t *s )
|
||||
{
|
||||
ll_node_t *n, *next=0;
|
||||
|
||||
if( !kill_last )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for( n=kill_last;
|
||||
n!=kill_last || next == 0 ;
|
||||
n=n->prev )
|
||||
{
|
||||
if( wcscmp( (wchar_t *)n->data, s ) == 0 )
|
||||
{
|
||||
kill_remove_node( n );
|
||||
break;
|
||||
}
|
||||
next = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void kill_replace( wchar_t *old, wchar_t *new )
|
||||
{
|
||||
kill_remove( old );
|
||||
kill_add( new );
|
||||
}
|
||||
|
||||
wchar_t *kill_yank_rotate()
|
||||
{
|
||||
@@ -133,49 +198,51 @@ static void kill_check_x_buffer()
|
||||
wchar_t *new_cut_buffer=0;
|
||||
array_list_t list;
|
||||
al_init( &list );
|
||||
exec_subshell( cmd, &list );
|
||||
|
||||
for( i=0; i<al_get_count( &list ); i++ )
|
||||
if( exec_subshell( cmd, &list ) != -1 )
|
||||
{
|
||||
wchar_t *next_line = escape( (wchar_t *)al_get( &list, i ), 0 );
|
||||
if( i==0 )
|
||||
|
||||
for( i=0; i<al_get_count( &list ); i++ )
|
||||
{
|
||||
new_cut_buffer = next_line;
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t *old = new_cut_buffer;
|
||||
new_cut_buffer= wcsdupcat2( new_cut_buffer, L"\\n", next_line, 0 );
|
||||
free( old );
|
||||
free( next_line );
|
||||
}
|
||||
}
|
||||
|
||||
if( new_cut_buffer )
|
||||
{
|
||||
/*
|
||||
The buffer is inserted with backslash escapes,
|
||||
since we don't really like tabs, newlines,
|
||||
etc. anyway.
|
||||
*/
|
||||
|
||||
if( cut_buffer != 0 )
|
||||
{
|
||||
if( wcscmp( new_cut_buffer, cut_buffer ) == 0 )
|
||||
wchar_t *next_line = escape( (wchar_t *)al_get( &list, i ), 0 );
|
||||
if( i==0 )
|
||||
{
|
||||
free( new_cut_buffer );
|
||||
new_cut_buffer = 0;
|
||||
new_cut_buffer = next_line;
|
||||
}
|
||||
else
|
||||
{
|
||||
free( cut_buffer );
|
||||
cut_buffer = 0;
|
||||
wchar_t *old = new_cut_buffer;
|
||||
new_cut_buffer= wcsdupcat2( new_cut_buffer, L"\\n", next_line, (void *)0 );
|
||||
free( old );
|
||||
free( next_line );
|
||||
}
|
||||
}
|
||||
if( cut_buffer == 0 )
|
||||
|
||||
if( new_cut_buffer )
|
||||
{
|
||||
cut_buffer = new_cut_buffer;
|
||||
kill_add_internal( cut_buffer );
|
||||
/*
|
||||
The buffer is inserted with backslash escapes,
|
||||
since we don't really like tabs, newlines,
|
||||
etc. anyway.
|
||||
*/
|
||||
|
||||
if( cut_buffer != 0 )
|
||||
{
|
||||
if( wcscmp( new_cut_buffer, cut_buffer ) == 0 )
|
||||
{
|
||||
free( new_cut_buffer );
|
||||
new_cut_buffer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
free( cut_buffer );
|
||||
cut_buffer = 0;
|
||||
}
|
||||
}
|
||||
if( cut_buffer == 0 )
|
||||
{
|
||||
cut_buffer = new_cut_buffer;
|
||||
kill_add_internal( cut_buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
kill.h
6
kill.h
@@ -9,6 +9,12 @@
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
/**
|
||||
Replace the specified string in the killring
|
||||
*/
|
||||
void kill_replace( wchar_t *old, wchar_t *new );
|
||||
|
||||
|
||||
/**
|
||||
Add a string to the top of the killring
|
||||
*/
|
||||
|
||||
94
main.c
94
main.c
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
Copyright (C) 2005 Axel Liljencrantz
|
||||
Copyright (C) 2005-2006 Axel Liljencrantz
|
||||
|
||||
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.
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -58,9 +58,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#include "exec.h"
|
||||
#include "event.h"
|
||||
#include "output.h"
|
||||
|
||||
#include "halloc.h"
|
||||
#include "halloc_util.h"
|
||||
#include "history.h"
|
||||
#include "path.h"
|
||||
|
||||
/**
|
||||
The string describing the single-character options accepted by the main fish binary
|
||||
@@ -75,23 +76,42 @@ static int read_init()
|
||||
char cwd[4096];
|
||||
wchar_t *wcwd;
|
||||
|
||||
wchar_t *config_dir;
|
||||
wchar_t *config_dir_escaped;
|
||||
void *context;
|
||||
string_buffer_t *eval_buff;
|
||||
|
||||
if( !getcwd( cwd, 4096 ) )
|
||||
{
|
||||
wperror( L"getcwd" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; and builtin . fish 2>/dev/null", 0, TOP );
|
||||
eval( L"builtin cd " SYSCONFDIR L" 2>/dev/null; and builtin . fish 2>/dev/null", 0, TOP );
|
||||
eval( L"builtin cd 2>/dev/null; and builtin . .fish 2>/dev/null", 0, TOP );
|
||||
|
||||
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; and builtin . config.fish 2>/dev/null", 0, TOP );
|
||||
eval( L"builtin cd " SYSCONFDIR L"/fish 2>/dev/null; and builtin . config.fish 2>/dev/null", 0, TOP );
|
||||
|
||||
/*
|
||||
We need to get the configuration directory before we can source the user configuration file
|
||||
*/
|
||||
context = halloc( 0, 0 );
|
||||
eval_buff = sb_halloc( context );
|
||||
config_dir = path_get_config( context );
|
||||
config_dir_escaped = escape( config_dir, 1 );
|
||||
sb_printf( eval_buff, L"builtin cd %ls 2>/dev/null; and builtin . config.fish 2>/dev/null", config_dir_escaped );
|
||||
eval( (wchar_t *)eval_buff->buff, 0, TOP );
|
||||
|
||||
halloc_free( context );
|
||||
free( config_dir_escaped );
|
||||
|
||||
if( chdir( cwd ) == -1 )
|
||||
{
|
||||
/*
|
||||
If we can't change back to previos directory, we'll stay in
|
||||
If we can't change back to previos directory, we go to
|
||||
~. Should be a sane default behavior.
|
||||
*/
|
||||
eval( L"builtin cd", 0, TOP );
|
||||
}
|
||||
|
||||
wcwd = str2wcs( cwd );
|
||||
if( wcwd )
|
||||
{
|
||||
@@ -102,28 +122,15 @@ static int read_init()
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Calls a bunch of init functions, parses the init files and then
|
||||
parses commands from stdin or files, depending on arguments
|
||||
*/
|
||||
|
||||
int main( int argc, char **argv )
|
||||
static int fish_parse_opt( int argc, char **argv, char **cmd_ptr )
|
||||
{
|
||||
int res=1;
|
||||
int force_interactive=0;
|
||||
int my_optind;
|
||||
int force_interactive=0;
|
||||
|
||||
char *cmd=0;
|
||||
|
||||
halloc_util_init();
|
||||
|
||||
wsetlocale( LC_ALL, L"" );
|
||||
is_interactive_session=1;
|
||||
program_name=L"fish";
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static struct option
|
||||
long_options[] =
|
||||
{
|
||||
@@ -173,11 +180,6 @@ int main( int argc, char **argv )
|
||||
long_options,
|
||||
&opt_index );
|
||||
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
@@ -190,7 +192,7 @@ int main( int argc, char **argv )
|
||||
|
||||
case 'c':
|
||||
{
|
||||
cmd = optarg;
|
||||
*cmd_ptr = optarg;
|
||||
is_interactive_session = 0;
|
||||
break;
|
||||
}
|
||||
@@ -213,7 +215,7 @@ int main( int argc, char **argv )
|
||||
|
||||
case 'h':
|
||||
{
|
||||
cmd = "help";
|
||||
*cmd_ptr = "help";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -252,7 +254,7 @@ int main( int argc, char **argv )
|
||||
|
||||
case '?':
|
||||
{
|
||||
return 1;
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -262,11 +264,34 @@ int main( int argc, char **argv )
|
||||
|
||||
is_login |= (strcmp( argv[0], "-fish") == 0);
|
||||
|
||||
is_interactive_session &= (cmd == 0);
|
||||
is_interactive_session &= (*cmd_ptr == 0);
|
||||
is_interactive_session &= (my_optind == argc);
|
||||
is_interactive_session &= isatty(STDIN_FILENO);
|
||||
is_interactive_session |= force_interactive;
|
||||
|
||||
return my_optind;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Calls a bunch of init functions, parses the init files and then
|
||||
parses commands from stdin or files, depending on arguments
|
||||
*/
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
int res=1;
|
||||
char *cmd=0;
|
||||
int my_optind=0;
|
||||
|
||||
halloc_util_init();
|
||||
|
||||
wsetlocale( LC_ALL, L"" );
|
||||
is_interactive_session=1;
|
||||
program_name=L"fish";
|
||||
|
||||
my_optind = fish_parse_opt( argc, argv, &cmd );
|
||||
|
||||
/*
|
||||
No-exec is prohibited when in interactive mode
|
||||
*/
|
||||
@@ -287,6 +312,7 @@ int main( int argc, char **argv )
|
||||
reader_init();
|
||||
history_init();
|
||||
|
||||
|
||||
if( read_init() )
|
||||
{
|
||||
if( cmd != 0 )
|
||||
|
||||
12
mimedb.c
12
mimedb.c
@@ -135,14 +135,10 @@ static int launch_len=0;
|
||||
*/
|
||||
static int launch_pos=0;
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
/**
|
||||
gettext alias
|
||||
*/
|
||||
#define _(string) gettext(string)
|
||||
#else
|
||||
#define _(string) (string)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Dynamically generated function, made from the documentation in doc_src.
|
||||
@@ -1145,10 +1141,8 @@ static void clear_entry( void *key, void *val )
|
||||
static void locale_init()
|
||||
{
|
||||
setlocale( LC_ALL, "" );
|
||||
#if HAVE_GETTEXT
|
||||
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
||||
textdomain( PACKAGE_NAME );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1174,7 +1168,6 @@ int main (int argc, char *argv[])
|
||||
*/
|
||||
while( 1 )
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static struct option
|
||||
long_options[] =
|
||||
{
|
||||
@@ -1228,11 +1221,6 @@ int main (int argc, char *argv[])
|
||||
long_options,
|
||||
&opt_index );
|
||||
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
|
||||
52
output.c
52
output.c
@@ -135,6 +135,11 @@ void output_set_writer( int (*writer)(char) )
|
||||
out = writer;
|
||||
}
|
||||
|
||||
int (*output_get_writer())(char)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void set_color( int c, int c2 )
|
||||
{
|
||||
@@ -336,34 +341,6 @@ void set_color( int c, int c2 )
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
perm_left_cursor and parm_right_cursor don't seem to be properly
|
||||
emulated by many terminal emulators, so we only use plain
|
||||
curor_left, curor_right...
|
||||
*/
|
||||
void move_cursor( int steps )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !steps )
|
||||
return;
|
||||
|
||||
if( steps < 0 ){
|
||||
for( i=0; i>steps; i--)
|
||||
{
|
||||
writembs(cursor_left);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<steps; i++)
|
||||
{
|
||||
writembs(cursor_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Default output method, simply calls write() on stdout
|
||||
*/
|
||||
@@ -553,25 +530,6 @@ int write_escaped_str( const wchar_t *str, int max_len )
|
||||
}
|
||||
|
||||
|
||||
int writespace( int c )
|
||||
{
|
||||
if( repeat_char && strlen(repeat_char) )
|
||||
{
|
||||
writembs( tparm( repeat_char, ' ', c ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i=0; i<c; i++ )
|
||||
{
|
||||
out( ' ' );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int output_color_code( const wchar_t *val )
|
||||
{
|
||||
int j, i, color=FISH_COLOR_NORMAL;
|
||||
|
||||
18
output.h
18
output.h
@@ -82,7 +82,7 @@ void set_color( int c, int c2 );
|
||||
int writembs( char *str );
|
||||
|
||||
/**
|
||||
Write a wide character to fd 1.
|
||||
Write a wide character using the output method specified using output_set_writer().
|
||||
*/
|
||||
int writech( wint_t ch );
|
||||
|
||||
@@ -102,23 +102,11 @@ void writestr_ellipsis( const wchar_t *str, int max_width );
|
||||
*/
|
||||
int write_escaped_str( const wchar_t *str, int max_len );
|
||||
|
||||
/**
|
||||
parm_ich seems to often be undefined, so we use this
|
||||
workalike. Writes the specified number of spaces.
|
||||
*/
|
||||
int writespace( int c );
|
||||
|
||||
/**
|
||||
Return the internal color code representing the specified color
|
||||
*/
|
||||
int output_color_code( const wchar_t *val );
|
||||
|
||||
/**
|
||||
perm_left_cursor and parm_right_cursor don't seem to be defined
|
||||
very often so we use cursor_left and cursor_right as a fallback.
|
||||
*/
|
||||
void move_cursor( int steps );
|
||||
|
||||
/**
|
||||
This is for writing process notification messages. Has to write to
|
||||
stdout, so clr_eol and such functions will work correctly. Not an
|
||||
@@ -134,5 +122,9 @@ int writeb( tputs_arg_t b );
|
||||
*/
|
||||
void output_set_writer( int (*writer)(char) );
|
||||
|
||||
//typedef int (*func_ptr_t)(char);
|
||||
|
||||
int (*output_get_writer())(char) ;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
247
parse_util.c
247
parse_util.c
@@ -2,6 +2,10 @@
|
||||
|
||||
Various mostly unrelated utility functions related to parsing,
|
||||
loading and evaluating fish code.
|
||||
|
||||
This library can be seen as a 'toolbox' for functions that are
|
||||
used in many places in fish and that are somehow related to
|
||||
parsing the code.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@@ -29,10 +33,22 @@
|
||||
#include "intern.h"
|
||||
#include "exec.h"
|
||||
#include "env.h"
|
||||
|
||||
#include "signal.h"
|
||||
#include "wildcard.h"
|
||||
#include "halloc_util.h"
|
||||
|
||||
/**
|
||||
Maximum number of autoloaded items opf a specific type to keep in
|
||||
memory at a time.
|
||||
*/
|
||||
#define AUTOLOAD_MAX 10
|
||||
|
||||
/**
|
||||
Minimum time, in seconds, before an autoloaded item will be
|
||||
unloaded
|
||||
*/
|
||||
#define AUTOLOAD_MIN_AGE 60
|
||||
|
||||
/**
|
||||
A structure representing the autoload state for a specific variable, e.g. fish_complete_path
|
||||
*/
|
||||
@@ -479,8 +495,18 @@ static void clear_hash_value( void *key, void *data, void *aux )
|
||||
if( aux )
|
||||
{
|
||||
wchar_t *name = (wchar_t *)key;
|
||||
time_t *time = (time_t *)data;
|
||||
void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
|
||||
handler( name );
|
||||
|
||||
/*
|
||||
If time[0] is 0, that means the file really doesn't exist,
|
||||
it's simply been checked before. We should not unload it.
|
||||
*/
|
||||
if( time[0] && handler )
|
||||
{
|
||||
// debug( 0, L"Unloading function %ls", name );
|
||||
handler( name );
|
||||
}
|
||||
}
|
||||
|
||||
free( (void *)data );
|
||||
@@ -527,14 +553,8 @@ static void parse_util_destroy()
|
||||
void parse_util_load_reset( const wchar_t *path_var_name,
|
||||
void (*on_load)(const wchar_t *cmd) )
|
||||
{
|
||||
wchar_t *path_var;
|
||||
|
||||
CHECK( path_var_name, );
|
||||
path_var = env_get( path_var_name );
|
||||
|
||||
if( !path_var )
|
||||
return;
|
||||
|
||||
if( all_loaded )
|
||||
{
|
||||
void *key, *data;
|
||||
@@ -580,34 +600,111 @@ int parse_util_unload( const wchar_t *cmd,
|
||||
return !!val;
|
||||
}
|
||||
|
||||
static void parse_util_autounload( const wchar_t *path_var_name,
|
||||
const wchar_t *skip,
|
||||
void (*on_load)(const wchar_t *cmd) )
|
||||
{
|
||||
autoload_t *loaded;
|
||||
int loaded_count=0;
|
||||
|
||||
if( !all_loaded )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
|
||||
if( !loaded )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( hash_get_count( &loaded->load_time ) >= AUTOLOAD_MAX )
|
||||
{
|
||||
time_t oldest_access = time(0) - AUTOLOAD_MIN_AGE;
|
||||
wchar_t *oldest_item=0;
|
||||
int i;
|
||||
array_list_t key;
|
||||
al_init( &key );
|
||||
hash_get_keys( &loaded->load_time, &key );
|
||||
for( i=0; i<al_get_count( &key ); i++ )
|
||||
{
|
||||
wchar_t *item = (wchar_t *)al_get( &key, i );
|
||||
time_t *tm = hash_get( &loaded->load_time, item );
|
||||
|
||||
if( wcscmp( item, skip ) == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !tm[0] )
|
||||
continue;
|
||||
|
||||
if( hash_get( &loaded->is_loading, item ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
loaded_count++;
|
||||
|
||||
if( tm[1] < oldest_access )
|
||||
{
|
||||
oldest_access = tm[1];
|
||||
oldest_item = item;
|
||||
}
|
||||
}
|
||||
al_destroy( &key );
|
||||
|
||||
if( oldest_item && loaded_count > AUTOLOAD_MAX)
|
||||
{
|
||||
parse_util_unload( oldest_item, path_var_name, on_load );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_util_load_internal( const wchar_t *cmd,
|
||||
void (*on_load)(const wchar_t *cmd),
|
||||
int reload,
|
||||
autoload_t *loaded,
|
||||
array_list_t *path_list );
|
||||
|
||||
|
||||
int parse_util_load( const wchar_t *cmd,
|
||||
const wchar_t *path_var_name,
|
||||
void (*on_load)(const wchar_t *cmd),
|
||||
int reload )
|
||||
{
|
||||
static array_list_t *path_list=0;
|
||||
static string_buffer_t *path=0;
|
||||
array_list_t *path_list=0;
|
||||
|
||||
int i;
|
||||
time_t *tm;
|
||||
int reloaded = 0;
|
||||
autoload_t *loaded;
|
||||
|
||||
wchar_t *path_var;
|
||||
|
||||
int res;
|
||||
int c, c2;
|
||||
|
||||
CHECK( path_var_name, 0 );
|
||||
CHECK( cmd, 0 );
|
||||
|
||||
CHECK_BLOCK( 0 );
|
||||
|
||||
// debug( 0, L"Autoload %ls in %ls", cmd, path_var_name );
|
||||
|
||||
parse_util_autounload( path_var_name, cmd, on_load );
|
||||
|
||||
path_var = env_get( path_var_name );
|
||||
|
||||
/*
|
||||
Do we know where to look
|
||||
Do we know where to look?
|
||||
*/
|
||||
if( !path_var )
|
||||
{
|
||||
// debug( 0, L"Path null" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Init if this is the first time we try to autoload anything
|
||||
*/
|
||||
if( !all_loaded )
|
||||
{
|
||||
all_loaded = malloc( sizeof( hash_table_t ) );
|
||||
@@ -623,12 +720,6 @@ int parse_util_load( const wchar_t *cmd,
|
||||
|
||||
if( loaded )
|
||||
{
|
||||
if( hash_get( &loaded->is_loading, cmd ) )
|
||||
{
|
||||
debug( 0, _(L"Could not autoload item %ls, it is already being autoloaded. This is a circular dependency in the autoloading scripts, please remove it."), cmd );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the lookup path has changed. If so, drop all loaded
|
||||
files and start from scratch.
|
||||
@@ -639,33 +730,102 @@ int parse_util_load( const wchar_t *cmd,
|
||||
reload = parse_util_load( cmd, path_var_name, on_load, reload );
|
||||
return reload;
|
||||
}
|
||||
|
||||
/**
|
||||
Warn and fail on infinite recursion
|
||||
*/
|
||||
if( hash_get( &loaded->is_loading, cmd ) )
|
||||
{
|
||||
debug( 0,
|
||||
_( L"Could not autoload item '%ls', it is already being autoloaded. "
|
||||
L"This is a circular dependency in the autoloading scripts, please remove it."),
|
||||
cmd );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We have never tried to autoload using this name before, set up initial data
|
||||
We have never tried to autoload using this path name before,
|
||||
set up initial data
|
||||
*/
|
||||
loaded = malloc( sizeof( autoload_t ) );
|
||||
// debug( 0, L"Create brand new autoload_t for %ls->%ls", path_var_name, path_var );
|
||||
loaded = malloc( sizeof( autoload_t ) );
|
||||
if( !loaded )
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
hash_init( &loaded->load_time, &hash_wcs_func, &hash_wcs_cmp );
|
||||
hash_put( all_loaded, wcsdup(path_var_name), loaded );
|
||||
|
||||
|
||||
hash_init( &loaded->is_loading, &hash_wcs_func, &hash_wcs_cmp );
|
||||
|
||||
loaded->old_path = wcsdup( path_var );
|
||||
}
|
||||
|
||||
hash_put( &loaded->is_loading, cmd, cmd );
|
||||
|
||||
path_list = al_new( global_context);
|
||||
|
||||
tokenize_variable_array( path_var, path_list );
|
||||
|
||||
c = al_get_count( path_list );
|
||||
|
||||
hash_put( &loaded->is_loading, cmd, cmd );
|
||||
|
||||
/*
|
||||
Do the actual work in the internal helper function
|
||||
*/
|
||||
|
||||
res = parse_util_load_internal( cmd, on_load, reload, loaded, path_list );
|
||||
|
||||
autoload_t *loaded2 = (autoload_t *)hash_get( all_loaded, path_var_name );
|
||||
if( loaded2 == loaded )
|
||||
{
|
||||
/**
|
||||
Cleanup
|
||||
*/
|
||||
hash_remove( &loaded->is_loading, cmd, 0, 0 );
|
||||
}
|
||||
|
||||
c2 = al_get_count( path_list );
|
||||
|
||||
al_foreach( path_list, &free );
|
||||
al_destroy( path_list );
|
||||
free( path_list );
|
||||
|
||||
/**
|
||||
Make sure we didn't 'drop' something
|
||||
*/
|
||||
|
||||
assert( c == c2 );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
This internal helper function does all the real work. By using two
|
||||
functions, the internal function can return on various places in
|
||||
the code, and the caller can take care of various cleanup work.
|
||||
*/
|
||||
|
||||
static int parse_util_load_internal( const wchar_t *cmd,
|
||||
void (*on_load)(const wchar_t *cmd),
|
||||
int reload,
|
||||
autoload_t *loaded,
|
||||
array_list_t *path_list )
|
||||
{
|
||||
static string_buffer_t *path=0;
|
||||
time_t *tm;
|
||||
int i;
|
||||
int reloaded = 0;
|
||||
|
||||
/*
|
||||
Get modification time of file
|
||||
*/
|
||||
tm = (time_t *)hash_get( &loaded->load_time, cmd );
|
||||
|
||||
|
||||
/*
|
||||
Did we just check this?
|
||||
*/
|
||||
@@ -673,7 +833,6 @@ int parse_util_load( const wchar_t *cmd,
|
||||
{
|
||||
if(time(0)-tm[1]<=1)
|
||||
{
|
||||
hash_remove( &loaded->is_loading, cmd, 0, 0 );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -683,20 +842,14 @@ int parse_util_load( const wchar_t *cmd,
|
||||
*/
|
||||
if( !reload && tm )
|
||||
{
|
||||
hash_remove( &loaded->is_loading, cmd, 0, 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !path_list )
|
||||
path_list = al_halloc( global_context);
|
||||
|
||||
if( !path )
|
||||
path = sb_halloc( global_context );
|
||||
else
|
||||
sb_clear( path );
|
||||
|
||||
tokenize_variable_array( path_var, path_list );
|
||||
|
||||
/*
|
||||
Iterate over path searching for suitable completion files
|
||||
*/
|
||||
@@ -706,6 +859,7 @@ int parse_util_load( const wchar_t *cmd,
|
||||
wchar_t *next = (wchar_t *)al_get( path_list, i );
|
||||
sb_clear( path );
|
||||
sb_append2( path, next, L"/", cmd, L".fish", (void *)0 );
|
||||
|
||||
if( (wstat( (wchar_t *)path->buff, &buf )== 0) &&
|
||||
(waccess( (wchar_t *)path->buff, R_OK ) == 0) )
|
||||
{
|
||||
@@ -713,6 +867,7 @@ int parse_util_load( const wchar_t *cmd,
|
||||
{
|
||||
wchar_t *esc = escape( (wchar_t *)path->buff, 1 );
|
||||
wchar_t *src_cmd = wcsdupcat( L". ", esc );
|
||||
free( esc );
|
||||
|
||||
if( !tm )
|
||||
{
|
||||
@@ -727,19 +882,33 @@ int parse_util_load( const wchar_t *cmd,
|
||||
intern( cmd ),
|
||||
tm );
|
||||
|
||||
free( esc );
|
||||
|
||||
if( on_load )
|
||||
on_load(cmd );
|
||||
|
||||
|
||||
/*
|
||||
Source the completion file for the specified completion
|
||||
*/
|
||||
exec_subshell( src_cmd, 0 );
|
||||
if( exec_subshell( src_cmd, 0 ) == -1 )
|
||||
{
|
||||
/*
|
||||
Do nothing on failiure
|
||||
*/
|
||||
}
|
||||
|
||||
free(src_cmd);
|
||||
reloaded = 1;
|
||||
break;
|
||||
}
|
||||
else if( tm )
|
||||
{
|
||||
/*
|
||||
If we are rechecking an autoload file, and it hasn't
|
||||
changed, update the 'last check' timestamp.
|
||||
*/
|
||||
tm[1] = time(0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -759,10 +928,6 @@ int parse_util_load( const wchar_t *cmd,
|
||||
hash_put( &loaded->load_time, intern( cmd ), tm );
|
||||
}
|
||||
|
||||
al_foreach( path_list, &free );
|
||||
al_truncate( path_list, 0 );
|
||||
|
||||
hash_remove( &loaded->is_loading, cmd, 0, 0 );
|
||||
return reloaded;
|
||||
}
|
||||
|
||||
|
||||
14
parse_util.h
14
parse_util.h
@@ -98,14 +98,16 @@ int parse_util_lineno( const wchar_t *str, int len );
|
||||
not load it multiple times unless it's timestamp changes or
|
||||
parse_util_unload is called.
|
||||
|
||||
Autoloading one file may unload another.
|
||||
|
||||
\param cmd the filename to search for. The suffix '.fish' is always added to this name
|
||||
\param path_var_name the environment variable giving the search path
|
||||
\param on_load a callback function to run if a suitable file is found, which has not already been run
|
||||
\param on_unload a callback function to run if a suitable file is found, which has not already been run. unload will also be called for old files which are unloaded.
|
||||
\param reload wheter to recheck file timestamps on already loaded files
|
||||
*/
|
||||
int parse_util_load( const wchar_t *cmd,
|
||||
const wchar_t *path_var_name,
|
||||
void (*on_load)(const wchar_t *cmd),
|
||||
void (*on_unload)(const wchar_t *cmd),
|
||||
int reload );
|
||||
|
||||
/**
|
||||
@@ -114,11 +116,10 @@ int parse_util_load( const wchar_t *cmd,
|
||||
reset.
|
||||
|
||||
\param path_var_name the environment variable giving the search path
|
||||
\param on_load the callback function to use when a file is reloaded
|
||||
\param on_load the callback function to call if the file has been previously loaded
|
||||
\param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file.
|
||||
*/
|
||||
void parse_util_load_reset( const wchar_t *path_var_name,
|
||||
void (*on_load)(const wchar_t *cmd) );
|
||||
void (*on_unload)(const wchar_t *cmd) );
|
||||
|
||||
/**
|
||||
Tell the autoloader that the specified file, in the specified path,
|
||||
@@ -126,11 +127,12 @@ void parse_util_load_reset( const wchar_t *path_var_name,
|
||||
|
||||
\param cmd the filename to search for. The suffix '.fish' is always added to this name
|
||||
\param path_var_name the environment variable giving the search path
|
||||
\param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file.
|
||||
\return non-zero if the file was removed, zero if the file had not yet been loaded
|
||||
*/
|
||||
int parse_util_unload( const wchar_t *cmd,
|
||||
const wchar_t *path_var_name,
|
||||
void (*on_load)(const wchar_t *cmd) );
|
||||
void (*on_unload)(const wchar_t *cmd) );
|
||||
|
||||
/**
|
||||
Set the argv environment variable to the specified null-terminated
|
||||
|
||||
63
parser.h
63
parser.h
@@ -12,6 +12,9 @@
|
||||
#include "parser.h"
|
||||
#include "event.h"
|
||||
|
||||
#define PARSER_TEST_ERROR 1
|
||||
#define PARSER_TEST_INCOMPLETE 2
|
||||
|
||||
/**
|
||||
event_block_t represents a block on events of the specified type
|
||||
*/
|
||||
@@ -54,6 +57,11 @@ typedef struct block
|
||||
The job that is currently evaluated in the specified block.
|
||||
*/
|
||||
job_t *job;
|
||||
|
||||
/**
|
||||
Block type-specific data
|
||||
*/
|
||||
void *data;
|
||||
|
||||
/**
|
||||
First block type specific variable
|
||||
@@ -62,11 +70,11 @@ typedef struct block
|
||||
{
|
||||
int while_state; /**< True if the loop condition has not yet been evaluated*/
|
||||
wchar_t *for_variable; /**< Name of the variable to loop over */
|
||||
int if_state; /**< The state of the if block */
|
||||
int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */
|
||||
wchar_t *switch_value; /**< The value to test in a switch block */
|
||||
wchar_t *function_name; /**< The name of the function to define or the function called*/
|
||||
const wchar_t *source_dest; /**< The name of the file to source*/
|
||||
event_t *event; /**<The event that triggered this block */
|
||||
wchar_t *function_call_name;
|
||||
} param1;
|
||||
|
||||
/**
|
||||
@@ -76,25 +84,9 @@ typedef struct block
|
||||
{
|
||||
array_list_t for_vars; /**< List of values for a for block */
|
||||
int switch_taken; /**< Whether a switch match has already been found */
|
||||
wchar_t *function_description; /**< The description of the function to define */
|
||||
process_t *function_call_process; /**< The process representing this function call */
|
||||
} param2;
|
||||
|
||||
/**
|
||||
Third block type specific variable
|
||||
*/
|
||||
union
|
||||
{
|
||||
int function_is_binding; /**< Whether a function is a keybinding */
|
||||
} param3;
|
||||
|
||||
/**
|
||||
Fourth block type specific variable
|
||||
*/
|
||||
union
|
||||
{
|
||||
array_list_t *function_events;
|
||||
} param4;
|
||||
|
||||
/**
|
||||
Name of file that created this block
|
||||
@@ -196,15 +188,6 @@ extern event_block_t *global_event_block;
|
||||
*/
|
||||
extern io_data_t *block_io;
|
||||
|
||||
/**
|
||||
Finds the full path of an executable in a newly allocated string.
|
||||
|
||||
\param cmd The name of the executable.
|
||||
\param context the halloc context to use for memory allocations
|
||||
\return 0 if the command can not be found, the path of the command otherwise.
|
||||
*/
|
||||
wchar_t *parser_get_filename( void *context, const wchar_t *cmd );
|
||||
|
||||
/**
|
||||
Evaluate the expressions contained in cmd.
|
||||
|
||||
@@ -313,11 +296,17 @@ const wchar_t *parser_get_block_desc( int block );
|
||||
|
||||
/**
|
||||
Test if the specified string can be parsed, or if more bytes need
|
||||
to be read first. The result has the first bit set if the string
|
||||
contains errors, and the second bit is set if the string contains
|
||||
an unclosed block.
|
||||
to be read first. The result will have the PARSER_TEST_ERROR bit
|
||||
set if there is a syntax error in the code, and the
|
||||
PARSER_TEST_INCOMPLETE bit set if the code contains unclosed
|
||||
blocks.
|
||||
|
||||
\param buff the text buffer to test
|
||||
\param block_level if non-null, the block nesting level will be filled out into this array
|
||||
\param out if non-null, any errors in the command will be filled out into this buffer
|
||||
\param prefix the prefix string to prepend to each error message written to the \c out buffer
|
||||
*/
|
||||
int parser_test( const wchar_t * buff, string_buffer_t *out, const wchar_t *prefix );
|
||||
int parser_test( const wchar_t * buff, int *block_level, string_buffer_t *out, const wchar_t *prefix );
|
||||
|
||||
/**
|
||||
Test if the specified string can be parsed as an argument list,
|
||||
@@ -327,15 +316,6 @@ int parser_test( const wchar_t * buff, string_buffer_t *out, const wchar_t *pref
|
||||
*/
|
||||
int parser_test_args( const wchar_t * buff, string_buffer_t *out, const wchar_t *prefix );
|
||||
|
||||
/**
|
||||
Returns the full path of the specified directory. If the \c in is a
|
||||
full path to an existing directory, a copy of the string is
|
||||
returned. If \c in is a directory relative to one of the
|
||||
directories i the CDPATH, the full path is returned. If no
|
||||
directory can be found, 0 is returned.
|
||||
*/
|
||||
wchar_t *parser_cdpath_get( void *context, wchar_t *in );
|
||||
|
||||
/**
|
||||
Tell the parser that the specified function may not be run if not
|
||||
inside of a conditional block. This is to remove some possibilities
|
||||
@@ -377,5 +357,8 @@ const wchar_t *parser_current_filename();
|
||||
*/
|
||||
void parser_stack_trace( block_t *b, string_buffer_t *buff);
|
||||
|
||||
int parser_get_block_type( const wchar_t *cmd );
|
||||
const wchar_t *parser_get_block_command( int type );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user