feat: add global installer

This commit is contained in:
Price Hiller 2022-07-31 21:44:44 -05:00
parent 9c03a7742e
commit f38fe54387
855 changed files with 165683 additions and 283 deletions

@ -1 +0,0 @@
Subproject commit 7e0eee64df6c7c81a57792674646b5feaf89f263

@ -1 +0,0 @@
Subproject commit a411ef3e0992d4839f0732ebeb9823024afaaaa8

@ -1 +0,0 @@
Subproject commit 11258bcd48521b5bc7b683104bb0f5cb9375edee

@ -1 +0,0 @@
Subproject commit caa749d030d22168445c4cb97befd406d2828db0

@ -1 +0,0 @@
Subproject commit debe9c8ad191b68b143230eb7bee437caba9c74f

View File

@ -0,0 +1,2 @@
modules/** linguist-vendored
modules/Src/aloxaf/*.c -linguist-vendored

View File

@ -0,0 +1,42 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: ''
---
#### Describe the bug
A clear and concise description of what the bug is.
I can make sure:
- [ ] I am using the latest version of fzf-tab
- [ ] this is the minimal zshrc which can reproduce this bug
- [ ] fzf-tab is loaded after `compinit`
- [ ] fzf-tab is loaded after plugins which will wrap <kbd>Tab</kbd>, like [junegunn/fzf/completion.zsh](https://github.com/junegunn/fzf/blob/master/shell/completion.zsh)
- [ ] fzf-tab is loaded before zsh-autosuggestions, zsh-syntax-highlighting and fast-syntax-highlighting.
#### To Reproduce
Steps to reproduce the behavior:
1. Type '...'
2. Press <kbd>Tab</kbd>
4. See error
#### Expected behavior
A clear and concise description of what you expected to happen.
#### Screenshots
If applicable, add screenshots to help explain your problem.
#### Environment:
- OS: [e.g. Arch Linux]
- zsh version: [e.g. 5.8.1]
#### Minimal zshrc
If applicable, add a minimal zshrc to help us analyze.
#### Log
If applicable, use `C-x .` to trigger completion and provide the log.
If there are only three lines in your log, please make sure your fzf-tab is loaded with the correct order (see the checklist above).

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FR]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,11 @@
---
name: Question
about: Ask a question about fzf-tab
title: "[Q]"
labels: question
assignees: ''
---
**Describe your question**
A clear and concise description of your question.

View File

@ -0,0 +1,36 @@
name: ci
on:
pull_request:
push:
branches:
- master
jobs:
test:
name: run test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- name: checkout
uses: actions/checkout@v1
with:
fetch-depth: 1
- name: install zsh (ubuntu)
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get install zsh
- name: test completion (ubuntu)
if: matrix.os == 'ubuntu-latest'
run: cd test && zsh -f runtests.zsh fzftab.ztst
- name: build binary module
run: zsh -fc 'source ./fzf-tab.zsh && build-fzf-tab-module'
- name: test binary module (ubuntu)
if: matrix.os == 'ubuntu-latest'
run: cd test && zsh -f runtests.zsh fzftab.ztst

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019-2021 Aloxaf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,138 @@
# fzf-tab
[![CI](https://github.com/Aloxaf/fzf-tab/workflows/ci/badge.svg)](https://github.com/Aloxaf/fzf-tab/actions?query=workflow%3Aci)
[![GitHub license](https://img.shields.io/github/license/Aloxaf/fzf-tab)](https://github.com/Aloxaf/fzf-tab/blob/master/LICENSE)
Replace zsh's default completion selection menu with fzf!
[![asciicast](https://asciinema.org/a/293849.svg)](https://asciinema.org/a/293849)
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**
- [fzf-tab](#fzf-tab)
- [Install](#install)
- [Manual](#manual)
- [Antigen](#antigen)
- [Zinit](#zinit)
- [Oh-My-Zsh](#oh-my-zsh)
- [Prezto](#prezto)
- [Usage](#usage)
- [Configure](#configure)
- [Binary module](#binary-module)
- [Difference from other plugins](#difference-from-other-plugins)
- [Compatibility with other plugins](#compatibility-with-other-plugins)
- [Related projects](#related-projects)
<!-- markdown-toc end -->
# Install
**NOTE: fzf-tab needs to be loaded after `compinit`, but before plugins which will wrap widgets, such as [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) or [fast-syntax-highlighting](https://github.com/zdharma-continuum/fast-syntax-highlighting)!!**
### Manual
First, clone this repository.
```zsh
git clone https://github.com/Aloxaf/fzf-tab ~/somewhere
```
Then add the following line to your `~/.zshrc`.
```zsh
source ~/somewhere/fzf-tab.plugin.zsh
```
### Antigen
```zsh
antigen bundle Aloxaf/fzf-tab
```
### Zinit
```zsh
zinit light Aloxaf/fzf-tab
```
### Oh-My-Zsh
Clone this repository to your custom directory and then add `fzf-tab` to your plugin list.
```zsh
git clone https://github.com/Aloxaf/fzf-tab ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/fzf-tab
```
### Prezto
Clone this repository to your contrib directory and then add `fzf-tab` to your module list in `.zpreztorc`.
```zsh
git clone https://github.com/Aloxaf/fzf-tab $ZPREZTODIR/contrib/fzf-tab
```
# Usage
Just press <kbd>Tab</kbd> as usual~
Available keybindings:
- <kbd>Ctrl</kdb>+<kdb>Space</kbd>: select multiple results, can be configured by `fzf-bindings` tag
- <kbd>F1</kbd>/<kbd>F2</kbd>: switch between groups, can be configured by `switch-group` tag
- <kbd>/</kbd>: trigger continuous completion (useful when completing a deep path), can be configured by `continuous-trigger` tag
Available commands:
- `disable-fzf-tab`: disable fzf-tab and fallback to compsys
- `enable-fzf-tab`: enable fzf-tab
- `toggle-fzf-tab`: toggle the state of fzf-tab. This is also a zle widget.
## Configure
A common configuration is:
```zsh
# disable sort when completing `git checkout`
zstyle ':completion:*:git-checkout:*' sort false
# set descriptions format to enable group support
zstyle ':completion:*:descriptions' format '[%d]'
# set list-colors to enable filename colorizing
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
# preview directory's content with exa when completing cd
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'exa -1 --color=always $realpath'
# switch group using `,` and `.`
zstyle ':fzf-tab:*' switch-group ',' '.'
```
For more information, please see [Wiki#Configuration](https://github.com/Aloxaf/fzf-tab/wiki/Configuration).
## Binary module
By default, fzf-tab uses [zsh-ls-colors](https://github.com/xPMo/zsh-ls-colors) to parse and apply ZLS_COLORS if you have set the `list-colors` tag.
However, it is a pure zsh script and is slow if you have too many files to colorize.
fzf-tab is shipped with a binary module to speed up this process. You can build it with `build-fzf-tab-module`, then it will be enabled automatically.
# Difference from other plugins
fzf-tab doesn't do "complete", it just shows you the results of the default completion system.
So it works EVERYWHERE (variables, function names, directory stack, in-word completion, etc.).
And most of your configuration for default completion system is still valid.
# Compatibility with other plugins
Some plugins may also bind "^I" to their custom widget, like [fzf/shell/completion.zsh](https://github.com/junegunn/fzf/blob/master/shell/completion.zsh) or [ohmyzsh/lib/completion.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/master/lib/completion.zsh#L61-L73).
By default, fzf-tab will call the widget previously bound to "^I" to get the completion list. So there is no problem in most cases, unless fzf-tab is initialized before a plugin which doesn't handle the previous binding properly.
So if you find your fzf-tab doesn't work properly, **please make sure it is the last plugin to bind "^I"** (If you don't know what I mean, just put it to the end of your plugin list).
# Related projects
- https://github.com/lincheney/fzf-tab-completion (fzf tab completion for zsh, bash and GNU readline apps)

View File

@ -0,0 +1,3 @@
0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
0="${${(M)0:#/*}:-$PWD/$0}"
source "${0:A:h}/fzf-tab.zsh"

View File

@ -0,0 +1,399 @@
# temporarily change options
'builtin' 'local' '-a' '_ftb_opts'
[[ ! -o 'aliases' ]] || _ftb_opts+=('aliases')
[[ ! -o 'sh_glob' ]] || _ftb_opts+=('sh_glob')
[[ ! -o 'no_brace_expand' ]] || _ftb_opts+=('no_brace_expand')
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
# thanks Valodim/zsh-capture-completion
-ftb-compadd() {
# parse all options
local -A apre hpre dscrs _oad
local -a isfile _opts __ expl
zparseopts -E -a _opts P:=apre p:=hpre d:=dscrs X+:=expl O:=_oad A:=_oad D:=_oad f=isfile \
i: S: s: I: x: r: R: W: F: M+: E: q e Q n U C \
J:=__ V:=__ a=__ l=__ k=__ o=__ 1=__ 2=__
# just delegate and leave if any of -O, -A or -D are given or fzf-tab is not enabled
if (( $#_oad != 0 || ! IN_FZF_TAB )); then
builtin compadd "$@"
return
fi
# store matches in $__hits and descriptions in $__dscr
local -a __hits __dscr
if (( $#dscrs == 1 )); then
__dscr=( "${(@P)${(v)dscrs}}" )
fi
builtin compadd -A __hits -D __dscr "$@"
local ret=$?
if (( $#__hits == 0 )); then
return $ret
fi
# store $curcontext for furthur usage
_ftb_curcontext=${curcontext#:}
# only store the fist `-X`
expl=$expl[2]
# keep order of group description
[[ -n $expl ]] && _ftb_groups+=$expl
# store these values in _ftb_compcap
local -a keys=(apre hpre PREFIX SUFFIX IPREFIX ISUFFIX)
local key expanded __tmp_value=$'<\0>' # placeholder
for key in $keys; do
expanded=${(P)key}
if [[ -n $expanded ]]; then
__tmp_value+=$'\0'$key$'\0'$expanded
fi
done
if [[ -n $expl ]]; then
# store group index
__tmp_value+=$'\0group\0'$_ftb_groups[(ie)$expl]
fi
if [[ -n $isfile ]]; then
# NOTE: need a extra ${} here or ~ expansion won't work
__tmp_value+=$'\0realdir\0'${${(Qe)~${:-$IPREFIX$hpre}}}
fi
_opts+=("${(@kv)apre}" "${(@kv)hpre}" $isfile)
__tmp_value+=$'\0args\0'${(pj:\1:)_opts}
if (( $+builtins[fzf-tab-compcap-generate] )); then
fzf-tab-compcap-generate __hits __dscr __tmp_value
else
# dscr - the string to show to users
# word - the string to be inserted
local dscr word i
for i in {1..$#__hits}; do
word=$__hits[i] dscr=$__dscr[i]
if [[ -n $dscr ]]; then
dscr=${dscr//$'\n'}
elif [[ -n $word ]]; then
dscr=$word
fi
_ftb_compcap+=$dscr$'\2'$__tmp_value$'\0word\0'$word
done
fi
# tell zsh that the match is successful
builtin compadd -U -qS '' -R -ftb-remove-space ''
}
# when insert multi results, a whitespace will be added to each result
# remove left space of our fake result because I can't remove right space
# FIXME: what if the left char is not whitespace: `echo $widgets[\t`
-ftb-remove-space() {
[[ $LBUFFER[-1] == ' ' ]] && LBUFFER[-1]=''
}
-ftb-zstyle() {
zstyle $1 ":fzf-tab:$_ftb_curcontext" ${@:2}
}
-ftb-complete() {
local -a _ftb_compcap
local -Ua _ftb_groups
local choice choices _ftb_curcontext continuous_trigger print_query accept_line bs=$'\2' nul=$'\0'
local ret=0
# must run with user options; don't move `emulate -L zsh` above this line
(( $+builtins[fzf-tab-compcap-generate] )) && fzf-tab-compcap-generate -i
COLUMNS=500 _ftb__main_complete "$@" || ret=$?
(( $+builtins[fzf-tab-compcap-generate] )) && fzf-tab-compcap-generate -o
emulate -L zsh -o extended_glob
local _ftb_query _ftb_complist=() _ftb_headers=() command opts
-ftb-generate-complist # sets `_ftb_complist`
-ftb-zstyle -s continuous-trigger continuous_trigger || {
[[ $OSTYPE == msys ]] && continuous_trigger=// || continuous_trigger=/
}
case $#_ftb_complist in
0) return 1;;
1)
choices=("EXPECT_KEY" "${_ftb_compcap[1]%$bs*}")
if (( _ftb_continue_last )); then
choices[1]=$continuous_trigger
fi
;;
*)
-ftb-generate-query # sets `_ftb_query`
-ftb-generate-header # sets `_ftb_headers`
-ftb-zstyle -s print-query print_query || print_query=alt-enter
-ftb-zstyle -s accept-line accept_line
choices=("${(@f)"$(builtin print -rl -- $_ftb_headers $_ftb_complist | -ftb-fzf)"}")
ret=$?
# choices=(query_string expect_key returned_word)
# insert query string directly
if [[ $choices[2] == $print_query ]] || [[ -n $choices[1] && $#choices == 1 ]] ; then
local -A v=("${(@0)${_ftb_compcap[1]}}")
local -a args=("${(@ps:\1:)v[args]}")
[[ -z $args[1] ]] && args=() # don't pass an empty string
IPREFIX=$v[IPREFIX] PREFIX=$v[PREFIX] SUFFIX=$v[SUFFIX] ISUFFIX=$v[ISUFFIX]
# NOTE: should I use `-U` here?, ../f\tabcd -> ../abcd
builtin compadd "${args[@]:--Q}" -Q -- $choices[1]
compstate[list]=
compstate[insert]=
if (( $#choices[1] > 0 )); then
compstate[insert]='2'
[[ $RBUFFER == ' '* ]] || compstate[insert]+=' '
fi
return $ret
fi
choices[1]=()
choices=("${(@)${(@)choices%$nul*}#*$nul}")
unset CTXT
;;
esac
if [[ -n $choices[1] && $choices[1] == $continuous_trigger ]]; then
typeset -gi _ftb_continue=1
typeset -gi _ftb_continue_last=1
fi
if [[ -n $choices[1] && $choices[1] == $accept_line ]]; then
typeset -gi _ftb_accept=1
fi
choices[1]=()
for choice in "$choices[@]"; do
local -A v=("${(@0)${_ftb_compcap[(r)${(b)choice}$bs*]#*$bs}}")
local -a args=("${(@ps:\1:)v[args]}")
[[ -z $args[1] ]] && args=() # don't pass an empty string
IPREFIX=$v[IPREFIX] PREFIX=$v[PREFIX] SUFFIX=$v[SUFFIX] ISUFFIX=$v[ISUFFIX]
builtin compadd "${args[@]:--Q}" -Q -- "$v[word]"
done
compstate[list]=
compstate[insert]=
if (( $#choices == 1 )); then
compstate[insert]='2'
[[ $RBUFFER == ' '* ]] || compstate[insert]+=' '
elif (( $#choices > 1 )); then
compstate[insert]='all'
fi
return $ret
}
fzf-tab-debug() {
(( $+_ftb_debug_cnt )) || typeset -gi _ftb_debug_cnt
local tmp=${TMPPREFIX:-/tmp/zsh}-$$-fzf-tab-$(( ++_ftb_debug_cnt )).log
local -i debug_fd=-1 IN_FZF_TAB=1
{
exec {debug_fd}>&2 2>| $tmp
local -a debug_indent; debug_indent=( '%'{3..20}'(e. .)' )
local PROMPT4 PS4="${(j::)debug_indent}+%N:%i> "
setopt xtrace
: $ZSH_NAME $ZSH_VERSION
zle .fzf-tab-orig-$_ftb_orig_widget
unsetopt xtrace
if (( debug_fd != -1 )); then
zle -M "fzf-tab-debug: Trace output left in $tmp"
fi
} always {
(( debug_fd != -1 )) && exec 2>&$debug_fd {debug_fd}>&-
}
}
fzf-tab-complete() {
# this name must be ugly to avoid clashes
local -i _ftb_continue=1 _ftb_continue_last=0 _ftb_accept=0 ret=0
# hide the cursor until finishing completion, so that users won't see cursor up and down
# NOTE: MacOS Terminal doesn't support civis & cnorm
echoti civis >/dev/tty 2>/dev/null
while (( _ftb_continue )); do
_ftb_continue=0
local IN_FZF_TAB=1
{
zle .fzf-tab-orig-$_ftb_orig_widget
ret=$?
} always {
IN_FZF_TAB=0
}
if (( _ftb_continue )); then
zle .split-undo
zle .reset-prompt
zle -R
zle fzf-tab-dummy
fi
done
echoti cnorm >/dev/tty 2>/dev/null
zle .redisplay
(( _ftb_accept )) && zle .accept-line
return $ret
}
# this function does nothing, it is used to be wrapped by other plugins like f-sy-h.
# this make it possible to call the wrapper function without causing any other side effects.
fzf-tab-dummy() { }
zle -N fzf-tab-debug
zle -N fzf-tab-complete
zle -N fzf-tab-dummy
disable-fzf-tab() {
emulate -L zsh -o extended_glob
(( $+_ftb_orig_widget )) || return 0
bindkey '^I' $_ftb_orig_widget
case $_ftb_orig_list_grouped in
0) zstyle ':completion:*' list-grouped false ;;
1) zstyle ':completion:*' list-grouped true ;;
2) zstyle -d ':completion:*' list-grouped ;;
esac
unset _ftb_orig_widget _ftb_orig_list_groupded
# unhook compadd so that _approximate can work properply
unfunction compadd 2>/dev/null
functions[_main_complete]=$functions[_ftb__main_complete]
functions[_approximate]=$functions[_ftb__approximate]
# Don't remove .fzf-tab-orig-$_ftb_orig_widget as we won't be able to reliably
# create it if enable-fzf-tab is called again.
}
enable-fzf-tab() {
emulate -L zsh -o extended_glob
(( ! $+_ftb_orig_widget )) || disable-fzf-tab
typeset -g _ftb_orig_widget="${${$(builtin bindkey '^I')##* }:-expand-or-complete}"
if (( ! $+widgets[.fzf-tab-orig-$_ftb_orig_widget] )); then
# Widgets that get replaced by compinit.
local compinit_widgets=(
complete-word
delete-char-or-list
expand-or-complete
expand-or-complete-prefix
list-choices
menu-complete
menu-expand-or-complete
reverse-menu-complete
)
# Note: We prefix the name of the widget with '.' so that it doesn't get wrapped.
if [[ $widgets[$_ftb_orig_widget] == builtin &&
$compinit_widgets[(Ie)$_ftb_orig_widget] != 0 ]]; then
# We are initializing before compinit and being asked to fall back to a completion
# widget that isn't defined yet. Create our own copy of the widget ahead of time.
zle -C .fzf-tab-orig-$_ftb_orig_widget .$_ftb_orig_widget _main_complete
else
# Copy the widget before it's wrapped by zsh-autosuggestions and zsh-syntax-highlighting.
zle -A $_ftb_orig_widget .fzf-tab-orig-$_ftb_orig_widget
fi
fi
zstyle -t ':completion:*' list-grouped false
typeset -g _ftb_orig_list_grouped=$?
zstyle ':completion:*' list-grouped false
bindkey -M emacs '^I' fzf-tab-complete
bindkey -M viins '^I' fzf-tab-complete
bindkey -M emacs '^X.' fzf-tab-debug
bindkey -M viins '^X.' fzf-tab-debug
# make sure we can copy them
autoload +X -Uz _main_complete _approximate
# hook compadd
functions[compadd]=$functions[-ftb-compadd]
# hook _main_complete to trigger fzf-tab
functions[_ftb__main_complete]=$functions[_main_complete]
function _main_complete() { -ftb-complete "$@" }
# TODO: This is not a full support, see #47
# _approximate will also hook compadd
# let it call -ftb-compadd instead of builtin compadd so that fzf-tab can capture result
# make sure _approximate has been loaded.
functions[_ftb__approximate]=$functions[_approximate]
function _approximate() {
# if not called by fzf-tab, don't do anything with compadd
(( ! IN_FZF_TAB )) || unfunction compadd
_ftb__approximate
(( ! IN_FZF_TAB )) || functions[compadd]=$functions[-ftb-compadd]
}
}
toggle-fzf-tab() {
emulate -L zsh -o extended_glob
if (( $+_ftb_orig_widget )); then
disable-fzf-tab
else
enable-fzf-tab
fi
}
build-fzf-tab-module() {
local MACOS
if [[ ${OSTYPE} == darwin* ]]; then
MACOS=true
fi
pushd $FZF_TAB_HOME/modules
CPPFLAGS=-I/usr/local/include CFLAGS="-g -Wall -O2" LDFLAGS=-L/usr/local/lib ./configure --disable-gdbm --without-tcsetpgrp ${MACOS:+DL_EXT=bundle}
make -j$(nproc)
popd
}
zmodload zsh/zutil
zmodload zsh/mapfile
zmodload -F zsh/stat b:zstat
0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
0="${${(M)0:#/*}:-$PWD/$0}"
FZF_TAB_HOME="${0:A:h}"
source "$FZF_TAB_HOME"/lib/zsh-ls-colors/ls-colors.zsh fzf-tab-lscolors
typeset -ga _ftb_group_colors=(
$'\x1b[94m' $'\x1b[32m' $'\x1b[33m' $'\x1b[35m' $'\x1b[31m' $'\x1b[38;5;27m' $'\x1b[36m'
$'\x1b[38;5;100m' $'\x1b[38;5;98m' $'\x1b[91m' $'\x1b[38;5;80m' $'\x1b[92m'
$'\x1b[38;5;214m' $'\x1b[38;5;165m' $'\x1b[38;5;124m' $'\x1b[38;5;120m'
)
# init
() {
emulate -L zsh -o extended_glob
fpath+=($FZF_TAB_HOME/lib)
autoload -Uz -- $FZF_TAB_HOME/lib/-#ftb*(:t)
if (( $+FZF_TAB_COMMAND || $+FZF_TAB_OPTS || $+FZF_TAB_QUERY || $+FZF_TAB_SINGLE_GROUP || $+fzf_tab_preview_init )) \
|| zstyle -m ":fzf-tab:*" command '*' \
|| zstyle -m ":fzf-tab:*" extra-opts '*'; then
print -P "%F{red}%B[fzf-tab] Sorry, your configuration is not supported anymore\n" \
"See https://github.com/Aloxaf/fzf-tab/pull/132 for more information%f%b"
fi
if [[ -n $FZF_TAB_HOME/modules/Src/aloxaf/fzftab.(so|bundle)(#qN) ]]; then
module_path+=("$FZF_TAB_HOME/modules/Src")
zmodload aloxaf/fzftab
if [[ $FZF_TAB_MODULE_VERSION != "0.2.2" ]]; then
zmodload -u aloxaf/fzftab
local rebuild
print -Pn "%F{yellow}fzftab module needs to be rebuild, rebuild now?[Y/n]:%f"
read -q rebuild
if [[ $rebuild == y ]]; then
build-fzf-tab-module
zmodload aloxaf/fzftab
fi
fi
fi
}
enable-fzf-tab
zle -N toggle-fzf-tab
# restore options
(( ${#_ftb_opts} )) && setopt ${_ftb_opts[@]}
'builtin' 'unset' '_ftb_opts'

View File

@ -0,0 +1,34 @@
#!/hint/zsh
emulate -L zsh -o cbases -o octalzeroes
local REPLY
local -a reply stat lstat
# fzf-tab-lscolors::match-by $1 lstat follow
zstat -A lstat -L -- $1
# follow symlink
(( lstat[3] & 0170000 )) && zstat -A stat -- $1 2>/dev/null
fzf-tab-lscolors::from-mode "$1" "$lstat[3]" $stat[3]
# fall back to name
[[ -z $REPLY ]] && fzf-tab-lscolors::from-name $1
# If this is a symlink
if [[ -n $lstat[14] ]]; then
local sym_color=$REPLY
local rsv_color=$REPLY
local rsv=$lstat[14]
# If this is not a broken symlink
if [[ -e $rsv ]]; then
# fzf-tab-lscolors::match-by $rsv stat
zstat -A stat -- $rsv
fzf-tab-lscolors::from-mode $rsv $stat[3]
# fall back to name
[[ -z $REPLY ]] && fzf-tab-lscolors::from-name $rsv
rsv_color=$REPLY
fi
dpre=$'\033[0m\033['$sym_color'm'
dsuf+=$'\033[0m -> \033['$rsv_color'm'$rsv
else
dpre=$'\033[0m\033['$REPLY'm'
fi

View File

@ -0,0 +1,102 @@
#!/hint/zsh
local tmp_dir=${TMPPREFIX:-/tmp/zsh}-fzf-tab-$USER
[[ -d $tmp_dir ]] || command mkdir $tmp_dir
local ftb_preview_init="
zmodload zsh/mapfile
local -a _ftb_compcap=(\"\${(@f)mapfile[$tmp_dir/compcap.$$]}\")
local -a _ftb_groups=(\"\${(@f)mapfile[$tmp_dir/groups.$$]}\")
local bs=\$'\2'
# get descriptoin
export desc=\${\${\"\$(<{f})\"%\$'\0'*}#*\$'\0'}
# get ctxt for current completion
local -A ctxt=(\"\${(@0)\${_ftb_compcap[(r)\${(b)desc}\$bs*]#*\$bs}}\")
# get group
if (( \$+ctxt[group] )); then
export group=\$_ftb_groups[\$ctxt[group]]
fi
# get original word
export word=\${(Q)ctxt[word]}
# get real path if it is file
if (( \$+ctxt[realdir] )); then
export realpath=\${ctxt[realdir]}\$word
fi
"
local binds=tab:down,btab:up,change:top,ctrl-space:toggle
local fzf_command fzf_flags fzf_preview debug_command tmp switch_group fzf_pad
local ret=0
-ftb-zstyle -s fzf-command fzf_command || fzf_command=fzf
-ftb-zstyle -a fzf-bindings tmp && binds+=,${(j:,:)tmp}
-ftb-zstyle -a fzf-flags fzf_flags
-ftb-zstyle -s fzf-preview fzf_preview
-ftb-zstyle -a switch-group switch_group || switch_group=(F1 F2)
-ftb-zstyle -s fzf-pad fzf_pad || fzf_pad=2
-ftb-zstyle -a debug-command debug_command && {
${(eX)debug_command} $fzf_flags
return
}
print -rl -- $_ftb_compcap > $tmp_dir/compcap.$$
print -rl -- $_ftb_groups > $tmp_dir/groups.$$
print -r -- ${ftb_preview_init/{f}/\$1} > $tmp_dir/ftb_preview_init.$$
binds=${binds//{_FTB_INIT_}/. $tmp_dir/ftb_preview_init.$$ {f} $'\n'}
local -i header_lines=$#_ftb_headers
local -i lines=$(( $#_ftb_compcap + fzf_pad + header_lines ))
local reload_command="$commands[zsh] -f $FZF_TAB_HOME/lib/ftb-switch-group $$ $header_lines $tmp_dir"
# detect if we will use tmux popup
local use_tmux_popup=0
if [[ $fzf_command == "ftb-tmux-popup" ]]; then
use_tmux_popup=1
fi
if (( ! use_tmux_popup )); then
# fzf will cause the current line to refresh, so move the cursor down.
echoti cud1 >/dev/tty
# reset cursor before call fzf
echoti cnorm >/dev/tty 2>/dev/null
fi
cat > $tmp_dir/completions.$$
local dd='gdd'
if (( ${+commands[$dd]} == 0 )) ; then
dd='dd'
fi
if (( ${+commands[$dd]} == 0 )) ; then
dd='true' # nop if dd is not installed
fi
_ftb_query="${_ftb_query}$(command "$dd" bs=1G count=1 status=none iflag=nonblock < /dev/tty 2>/dev/null)" || true
$fzf_command \
--ansi \
--bind=$binds \
--bind="${switch_group[1]}:reload($reload_command -1),${switch_group[2]}:reload($reload_command 1)" \
--color=hl:$(( header_lines == 0 ? 188 : 255 )) \
--cycle \
--delimiter='\x00' \
--expect=$continuous_trigger,$print_query,$accept_line \
--header-lines=$header_lines \
--height=${FZF_TMUX_HEIGHT:=$(( lines > LINES / 3 * 2 ? LINES / 3 * 2 : lines ))} \
--layout=reverse \
--multi \
--nth=2,3 \
--print-query \
--query=$_ftb_query \
--tiebreak=begin \
${fzf_preview:+--preview=$ftb_preview_init$fzf_preview} \
$fzf_flags < $tmp_dir/completions.$$ || ret=$?
if (( ! use_tmux_popup )); then
echoti civis >/dev/tty 2>/dev/null
echoti cuu1 >/dev/tty
fi
command rm $tmp_dir/*.$$ 2>/dev/null
return $ret

View File

@ -0,0 +1,113 @@
#!/hint/zsh
local dsuf dpre k _v filepath first_word show_group default_color prefix bs=$'\b'
local -a list_colors group_colors tcandidates reply match mbegin mend
local -i same_word=1 colorful=0
local -Ua duplicate_groups=()
local -A word_map=()
(( $#_ftb_compcap == 0 )) && return
-ftb-zstyle -s show-group show_group || show_group=full
-ftb-zstyle -s default-color default_color || default_color=$'\x1b[37m'
-ftb-zstyle -s prefix prefix || {
zstyle -m ':completion:*:descriptions' format '*' && prefix='·'
}
-ftb-zstyle -a group-colors group_colors || group_colors=($_ftb_group_colors)
zstyle -a ":completion:$_ftb_curcontext" list-colors list_colors
# init colorize
if (( $+builtins[fzf-tab-candidates-generate] )); then
fzf-tab-candidates-generate -i list_colors
else
local -A namecolors=(${(@s:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
local -A modecolors=(${(@Ms:=:)${(@s.:.)list_colors}:#[[:alpha:]][[:alpha:]]=*})
(( $#namecolors == 0 && $#modecolors == 0 )) && list_colors=()
fi
if (( $#_ftb_groups == 1 )); then
-ftb-zstyle -m single-group prefix || prefix=''
-ftb-zstyle -m single-group color || group_colors=("$default_color")
fi
if (( $+builtins[fzf-tab-candidates-generate] )); then
fzf-tab-candidates-generate
else
for k _v in "${(@ps:\2:)_ftb_compcap}"; do
local -A v=("${(@0)_v}")
[[ $v[word] == ${first_word:=$v[word]} ]] || same_word=0
# add character and color to describe the type of the files
dsuf='' dpre=''
if (( $+v[realdir] )); then
filepath=$v[realdir]${(Q)v[word]}
if [[ -d $filepath ]]; then
dsuf=/
fi
# add color and resolve symlink if have list-colors
# detail: http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html#The-zsh_002fcomplist-Module
if (( $#list_colors )) && [[ -a $filepath || -L $filepath ]]; then
-ftb-colorize $filepath
colorful=1
elif [[ -L $filepath ]]; then
dsuf=@
fi
if [[ $options[list_types] == off ]]; then
dsuf=''
fi
fi
# add color to description if they have group index
if (( $+v[group] )); then
local color=$group_colors[$v[group]]
# add a hidden group index at start of string to keep group order when sorting
# first group index is for builtin sort, sencond is for GNU sort
tcandidates+=$v[group]$'\b'$color$prefix$dpre$'\0'$v[group]$'\b'$k$'\0'$dsuf
else
tcandidates+=$default_color$dpre$'\0'$k$'\0'$dsuf
fi
# check group with duplicate member
if [[ $show_group == brief ]]; then
if (( $+word_map[$v[word]] && $+v[group] )); then
duplicate_groups+=$v[group] # add this group
duplicate_groups+=$word_map[$v[word]] # add previous group
fi
word_map[$v[word]]=$v[group]
fi
done
fi
(( same_word )) && tcandidates[2,-1]=()
# sort and remove sort group or other index
zstyle -T ":completion:$_ftb_curcontext" sort
if (( $? != 1 )); then
if (( colorful )); then
# if enable list_colors, we should skip the first field
if [[ ${commands[sort]:A:t} != (|busybox*) ]]; then
# this is faster but doesn't work if `find` is from busybox
tcandidates=(${(f)"$(command sort -u -t '\0' -k 2 <<< ${(pj:\n:)tcandidates})"})
else
# slower but portable
tcandidates=(${(@o)${(@)tcandidates:/(#b)([^$'\0']#)$'\0'(*)/$match[2]$'\0'$match[1]}})
tcandidates=(${(@)tcandidates/(#b)(*)$'\0'([^$'\0']#)/$match[2]$'\0'$match[1]})
fi
else
tcandidates=("${(@o)tcandidates}")
fi
fi
typeset -gUa _ftb_complist=("${(@)tcandidates//[0-9]#$bs}")
# hide needless group
if (( $#_ftb_groups )); then
local i to_hide indexs=({1..$#_ftb_groups})
case $show_group in
brief) to_hide=(${indexs:|duplicate_groups}) ;;
none) to_hide=($indexs) ;;
esac
for i in $to_hide; do
# NOTE: _ftb_groups is unique array
_ftb_groups[i]="__hide__$i"
done
fi

View File

@ -0,0 +1,35 @@
#!/hint/zsh
typeset -ga _ftb_headers=()
local i tmp group_colors
local -i mlen=0 len=0
if (( $#_ftb_groups == 1 )) && { ! -ftb-zstyle -m single-group "header" }; then
return
fi
# calculate the max column width
for i in $_ftb_groups; do
(( $#i > mlen )) && mlen=$#i
done
mlen+=1
-ftb-zstyle -a group-colors group_colors || group_colors=($_ftb_group_colors)
for (( i=1; i<=$#_ftb_groups; i++ )); do
[[ $_ftb_groups[i] == "__hide__"* ]] && continue
if (( len + $#_ftb_groups[i] > COLUMNS - 5 )); then
_ftb_headers+=$tmp
tmp='' && len=0
fi
if (( len + mlen > COLUMNS - 5 )); then
# the last column doesn't need padding
_ftb_headers+=$tmp$group_colors[i]$_ftb_groups[i]$'\033[00m'
tmp='' && len=0
else
tmp+=$group_colors[i]${(r:$mlen:)_ftb_groups[i]}$'\033[00m'
len+=$mlen
fi
done
(( $#tmp )) && _ftb_headers+=$tmp

View File

@ -0,0 +1,40 @@
#!/hint/zsh
if zmodload -s zsh/pcre; then
setopt localoptions rematch_pcre
fi
local key qtype tmp query_string
typeset -g _ftb_query=
-ftb-zstyle -a query-string query_string || query_string=(prefix input first)
for qtype in $query_string; do
if [[ $qtype == prefix ]]; then
# find the longest common prefix among descriptions
local -a keys=(${_ftb_compcap%$'\2'*})
tmp=$keys[1]
local MATCH match mbegin mend prefix=(${(s::)tmp})
for key in ${keys:1}; do
(( $#tmp )) || break
[[ $key == $tmp* ]] && continue
# interpose characters from the current common prefix and $key and see how
# many pairs of equal characters we get at the start of the resulting string
[[ ${(j::)${${(s::)key[1,$#tmp]}:^prefix}} =~ '^(((.)\3)*)' ]]
# truncate common prefix and maintain loop invariant: ${(s::)tmp} == $prefix
tmp[$#MATCH/2+1,-1]=""
prefix[$#MATCH/2+1,-1]=()
done
elif [[ $qtype == input ]]; then
local fv=${_ftb_compcap[1]#*$'\2'}
local -A v=("${(@0)fv}")
tmp=$v[PREFIX]
if (( $RBUFFER[(i)$v[SUFFIX]] != 1 )); then
tmp=${tmp/%$v[SUFFIX]}
fi
tmp=${${tmp#$v[hpre]}#$v[apre]}
fi
if (( $query_string[(I)longest] )); then
(( $#tmp > $#_ftb_query )) && _ftb_query=$tmp
elif [[ -n $tmp ]]; then
_ftb_query=$tmp && break
fi
done

View File

@ -0,0 +1,38 @@
#!/hint/zsh
emulate -L zsh -o extended_glob
zmodload zsh/mapfile
# receive arguments
local pid=$1 header_lines=$2 tmp_dir=$3 offset=$@[-1]
# read completion list
local -a list=(${(f)mapfile[$tmp_dir/completions.$pid]})
# get total group count
if (( $#list > 10000 )); then
local -Ua total=(${(f)"$(print -l ${list:$header_lines} | grep -a -oP '^\x1b\[[0-9;]*m')"})
else
local -Ua total=(${(M)${list:$header_lines}#$'\x1b['[0-9;]#*m})
fi
# get current group index, start from 2
local current=2
if [[ -f $tmp_dir/current-group.$pid ]]; then
current=$(( $(<$tmp_dir/current-group.$pid) + offset ))
fi
(( current > $#total )) && current=1
(( current == 0 )) && current=$#total
echo $current > $tmp_dir/current-group.$pid
# print headers
if (( header_lines != 0 )); then
print -l ${list[1,header_lines]/${total[current]}/$'\x1b[1m'}
fi
# print current group
if (( $#list > 10000 )); then
print -l ${list:$header_lines} | grep -a -F "${total[current]}"
else
print -l ${(M)${list:$header_lines}:#${total[current]}*}
fi

View File

@ -0,0 +1,88 @@
#!/hint/zsh
# Show results with tmux popup
# Example usage:
# zstyle ':fzf-tab:*' fzf-command ftb-tmux-popup
# zstyle ':fzf-tab:*' popup-pad 0 0
# It can also be used as a standalone tool, like:
# ls | ftb-tmux-popup
emulate -L zsh -o extended_glob
# import min
autoload -Uz zmathfunc
zmathfunc
: ${tmp_dir:=${TMPPREFIX:-/tmp/zsh}-fzf-tab-$USER}
# fallback to fzf if it is not running in tmux
if (( ! $+TMUX_PANE )); then
fzf $@
return
fi
local ret=0
local -a fzf_opts=($@)
fzf_opts=(${${fzf_opts/--height*}/--layout*})
# get position of cursor and size of window
local -a tmp=($(command tmux display-message -p "#{pane_top} #{cursor_y} #{pane_left} #{cursor_x} #{window_height} #{window_width} #{status} #{status-position}"))
local cursor_y=$((tmp[1] + tmp[2])) cursor_x=$((tmp[3] + tmp[4])) window_height=$tmp[5] window_width=$tmp[6] window_top=0
if [[ $tmp[8] == 'top' ]]; then
window_top=$tmp[7]
cursor_y=$((cursor_y + window_top))
fi
# if not called by fzf-tab
if (( ! $+IN_FZF_TAB )); then
[[ -d $tmp_dir ]] || mkdir -p $tmp_dir
cat > $tmp_dir/completions.$$
fi
local text REPLY comp_lines comp_length length popup_pad
zstyle -a ":fzf-tab:$_ftb_curcontext" popup-pad popup_pad || popup_pad=(0 0)
# get the size of content, note we should remove all ANSI color code
comp_lines=$(( ${#${(f)mapfile[$tmp_dir/completions.$$]}} + $popup_pad[2] ))
if (( comp_lines <= 500 )); then
comp_length=0
for line in ${(f)mapfile[$tmp_dir/completions.$$]}; do
length=${(m)#${(S)line//$'\x1b['[0-9]#*m}}
(( length >= comp_length )) && comp_length=$length
done
else
# FIXME: can't get the correct width of CJK characters.
comp_length=$( command perl -ne 's/\x1b\[[0-9;]*m//g;s/\x00//g; $m= length() if $m < length(); END { print $m }' < $tmp_dir/completions.$$ )
fi
comp_length=$(( comp_length + $popup_pad[1] ))
local popup_height popup_y popup_width popup_x
# calculate the popup height and y position
if (( cursor_y * 2 > window_height )); then
# show above the cursor
popup_height=$(( min(comp_lines + 4, cursor_y - window_top) ))
popup_y=$cursor_y
else
# show below the cursor
popup_height=$(( min(comp_lines + 4, window_height - cursor_y + window_top - 1) ))
popup_y=$(( cursor_y + popup_height + 1 ))
fzf_opts+=(--layout=reverse)
fi
# calculate the popup width and x position
popup_width=$(( min(comp_length + 5, window_width) ))
popup_x=$(( cursor_x + popup_width > window_width ? window_width - popup_width : cursor_x ))
echo -E "$commands[fzf] ${(qq)fzf_opts[@]} < $tmp_dir/completions.$$ > $tmp_dir/result-$$" > $tmp_dir/fzf-$$
{
tmux popup -x $popup_x -y $popup_y \
-w $popup_width -h $popup_height \
-d $PWD -E ". $tmp_dir/fzf-$$" || ret=$?
echo -E "$(<$tmp_dir/result-$$)"
} always {
command rm $tmp_dir/*-$$
(( $+IN_FZF_TAB )) || command rm $tmp_dir/completions.$$
}
return $ret

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Gamma
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,114 @@
# zsh-ls-colors
![Demo screenshot](https://raw.githubusercontent.com/xPMo/zsh-ls-colors/image/demo.png)
A zsh library to use `LS_COLORS` in scripts or other plugins.
For a simple demo, see the `demo` script in this repo.
For more advanced usage,
instructions are located at top of the source files for `from-mode` and `from-name`.
If a use case isn't adequately covered,
please open an issue!
## Using zsh-ls-colors in a plugin
You can use this as a submodule or a subtree.
### submodule:
```sh
# Add (only once)
git submodule add git://github.com/xPMo/zsh-ls-colors.git ls-colors
git commit -m 'Add ls-colors as submodule'
# Update
cd ls-colors
git fetch
git checkout origin/master
cd ..
git commit ls-colors -m 'Update ls-colors to latest'
```
### Subtree:
```sh
# Initial add
git subtree add --prefix=ls-colors/ --squash -m 'Add ls-colors as a subtree' \
git://github.com/xPMo/zsh-ls-colors.git master
# Update
git subtree pull --prefix=ls-colors/ --squash -m 'Update ls-colors to latest' \
git://github.com/xPMo/zsh-ls-colors.git master
# Or, after adding a remote:
git remote add ls-colors git://github.com/xPMo/zsh-ls-colors.git
# Initial add
git subtree add --prefix=ls-colors/ --squash -m 'Add ls-colors as a subtree' ls-colors master
# Update
git subtree pull --prefix=ls-colors/ --squash -m 'Update ls-colors to latest' ls-colors master
```
### Function namespacing
Since functions are a public namespace,
this plugin allows you to customize the preifix for your plugin:
```zsh
# load functions as my-lscolors::{init,match-by,from-name,from-mode}
source ${0:h}/ls-colors/ls-colors.zsh my-lscolors
```
### Parameter namespacing
While indirect parameter expansion exists with `${(P)var}`,
it doesn't play nicely with array parameters.
There are multiple strategies to prevent unnecessary re-parsing:
```zsh
# Call once when loading.
# Pollutes global namespace but prevents re-parsing
ls-color::init
```
```zsh
# Don't call init at all and only use ::match-by.
# Doesn't pollute global namespace but reparses LS_COLORS on every call
ls-color::match-by $file lstat
```
```zsh
# Initialize within a scope with local parameters.
# Best for not polluting global namespace when multiple filenames need to be parsed.
(){
local -A namecolors modecolors
ls-color::init
for arg; do
...
done
}
```
```zsh
# Serialize:
typeset -g LS_COLORS_CACHE_FILE=$(mktemp)
(){
local -A namecolors modecolors
ls-color::init
typeset -p modecolors namecolors >| $LS_COLORS_CACHE_FILE
zcompile $LS_COLORS_CACHE_FILE
}
my-function(){
local -A namecolors modecolors
source $LS_COLORS_CACHE_FILE
...
}
```

View File

@ -0,0 +1,65 @@
#!/usr/bin/env zsh
# set $0 (ref: zdharma.org/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html#zero-handling)
0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}"
0="${${(M)0:#/*}:-$PWD/$0}"
# load library functions
source ls-colors.zsh ''
# to name the functions with a different namespace
# call source with a different argument
#source my-plugin::ls
# init (sets modecolors and namecolors)
# You have options. Either you can pollute global namespace:
ls-color::init
# Or you can have ::match-by re-parse colors on every call
: # (do nothing)
# Or if you have multiple calls, you can parse colors once for a scope:
(){
local -A modecolors namecolors
ls-color::init
for arg; do
ls-color::match-by $arg lstat
: do something else
done
}
# colors can also be added for other globs after init as well:
namecolors[*.md]='01' # bold markdown files
# EXTENDED_GLOB is enabled when matching, so things like this are possible:
namecolors[(#i)(*/|)license(|.*)]='04' # underline LICENSE, or license.txt, or similar
local file reply
# color each file in the argument list
for file; do
ls-color::match-by $file all
# point to symlink resolution if it exists
print '\e['$reply[1]'m'$file'\e[0m'${reply[2]:+' → \e['$reply[3]'m'$reply[2]'\e[0m'}
done
# =======================
# Alternate manual method:
for file; do
ls-color::match-by $file lstat follow
if [[ $reply[2] ]]; then
# This is a symlink
symlink_color=$reply[1]
# If broken, use link color for destination
resolved_color=$reply[1]
resolved=$reply[2]
if [[ -e $file ]]; then
# Not broken, update destination color
ls-color::match-by $file stat
resolved_color=$reply[1]
fi
print '\e['$symlink_color'm'$file'\e[0m → \e['$resolved_color'm'$resolved'\e[0m'
else
# This is not a symlink
print '\e['$reply[1]'m'$file'\e[0m'
fi
done

View File

@ -0,0 +1,186 @@
#!/usr/bin/env zsh
# set the prefix for all functions
local pfx=${1:-'ls-color'}
# {{{ From mode
# Usage:
# $1: filename
# $2: The value of struct stat st_mode
# If empty, modecolors lookup will be skipped
# $3: (If symlink) The value of struct stat st_mode
# for the target of $1's symlink. If unset,
# interpret as a broken link.
# Sets REPLY to the console code
${pfx}::from-mode () {
emulate -L zsh
setopt cbases octalzeroes extendedglob
[[ -z $2 ]] && return 1
local -i reg=0
local -a codes
local -i st_mode=$(($2))
# See man 7 inode for more info
# file type
case $(( st_mode & 0170000 )) in
$(( 0140000 )) ) codes=( $modecolors[so] ) ;;
$(( 0120000 )) ) # symlink, special handling
if ! (($+3)); then
REPLY=$modecolors[or]
elif [[ $modecolors[ln] = target ]]; then
"$0" "$1" "${@:3}"
else
REPLY=$modecolors[ln]
fi
return
;;
$(( 0100000 )) ) codes=( ); reg=1 ;; # regular file
$(( 0060000 )) ) codes=( $modecolors[bd] ) ;;
$(( 0040000 )) ) codes=( $modecolors[di] ) ;;
$(( 0020000 )) ) codes=( $modecolors[cd] ) ;;
$(( 0010000 )) ) codes=( $modecolors[pi] ) ;;
esac
# setuid/setgid/sticky/other-writable
(( st_mode & 04000 )) && codes+=( $modecolors[su] )
(( st_mode & 02000 )) && codes+=( $modecolors[sg] )
(( ! reg )) && case $(( st_mode & 01002 )) in
# sticky
$(( 01000 )) ) codes+=( $modecolors[st] ) ;;
# other-writable
$(( 00002 )) ) codes+=( $modecolors[ow] ) ;;
# other-writable and sticky
$(( 01002 )) ) codes+=( $modecolors[tw] ) ;;
esac
# executable
if (( ! $#codes )); then
(( st_mode & 0111 )) && codes+=( $modecolors[ex] )
fi
# return nonzero if no matching code
[[ ${REPLY::=${(j:;:)codes}} ]]
} # }}}
# {{{ From name
# Usage:
# $1: filename
#
# Sets REPLY to the console code
${pfx}::from-name () {
emulate -L zsh
setopt extendedglob
# Return non-zero if no keys match
[[ ${REPLY::=$namecolors[(k)$1]} ]]
} # }}}
# {{{ Init
# WARNING: initializes namecolors and modecolors in global scope
${pfx}::init () {
emulate -L zsh
# Use $1 if provided, otherwise use LS_COLORS
# Use LSCOLORS on BSD
local LS_COLORS=${1:-${LS_COLORS:-$LSCOLORS}}
# read in LS_COLORS
typeset -gA namecolors=(${(@s:=:)${(@s.:.)LS_COLORS}:#[[:alpha:]][[:alpha:]]=*})
typeset -gA modecolors=(${(@Ms:=:)${(@s.:.)LS_COLORS}:#[[:alpha:]][[:alpha:]]=*})
}
# }}}
# {{{ Match by
# Usage:
# $1: filename
# Optional (must be $2): g[lobal]: Use existing stat | lstat in parent scope
# ${@:2}: Append to reply:
# - l[stat] : Look up using lstat (don't follow symlink), if empty match name
# - s[tat] : Look up using stat (do follow symlink), if empty match name
# - n[ame] : Only match name
# - f[ollow]: Get resolution path of symlink
# - L[stat] : Same as above but don't match name
# - S[tat] : Same as above but don't match name
# - a[ll] : If a broken symlink: lstat follow lstat
# : If a symlink : lstat follow stat
# : Otherwise : lstat
# - A[ll] : If a broken symlink: Lstat follow Lstat
# : If a symlink : Lstat follow Stat
# : Otherwise : Lstat
#
# or returns non-zero
${pfx}::match-by () {
emulate -L zsh
setopt extendedglob cbases octalzeroes
local arg REPLY name=$1 pfx=${0%::match-by}
shift
# init in local scope if not using global params
if ! [[ -v namecolors && -v modecolors ]]; then
local -A namecolors modecolors
${pfx}::init
fi
if [[ ${1:l} = (g|global) ]]; then
shift
else
local -a stat lstat
declare -ga reply=()
fi
zmodload -F zsh/stat b:zstat
for arg; do
case ${arg[1]:l} in
n|name)
${pfx}::from-name $name
reply+=("$REPLY")
;;
l|lstat)
(($#lstat)) || zstat -A lstat -L $name || return 1
if ((lstat[3] & 0170000 )); then
# follow symlink
(($#stat)) || zstat -A stat $name 2>/dev/null
fi
${pfx}::from-mode "$name" "$lstat[3]" $stat[3]
if [[ $REPLY || ${2[1]} = L ]]; then
reply+=("$REPLY")
else # fall back to name
"$0" "$name" g n
fi
;;
s|stat)
(($#stat)) || zstat -A stat $name || return 1
${pfx}::from-mode $name $stat[3]
reply+=("$REPLY")
if [[ $REPLY || ${arg[1]} = S ]]; then
reply+=("$REPLY")
else # fall back to name
"$0" "$name" g n
fi
;;
f|follow)
(($#lstat)) || zstat -A lstat -L $name || return 1
reply+=("$lstat[14]")
;;
a|all)
# Match case
"$0" "$name" g ${${${arg[1]%a}:+L}:-l}
# won't append if empty
reply+=($lstat[14])
# $stat[14] will be empty if not a symlink
if [[ $lstat[14] ]]; then
if [[ -e $name ]]; then
"$0" "$name" g ${${${arg[1]%a}:+S}:-s}
else
reply+=($reply[-2])
fi
fi
;;
*) return 2 ;;
esac
done
}
# }}}
# vim: set foldmethod=marker:

View File

@ -0,0 +1,16 @@
Makefile
META-FAQ
config.cache
config.h
config.h.in
config.log
config.modules
config.modules.sh
config.status
configure
cscope.out
stamp-h
stamp-h.in
autom4te.cache
*.swp
.git

View File

@ -0,0 +1,4 @@
DISTFILES_SRC='
META-FAQ
configure config.h.in stamp-h.in
'

View File

@ -0,0 +1,15 @@
# Top-most editorconfig file
root = true
[*]
end_of_line = lf
tab_width = 8
indent_size = 2
indent_style = tab
[ChangeLog]
indent_size = 8
[*.[ch]]
indent_size = 4

View File

@ -0,0 +1,155 @@
Makefile
tags
TAGS
*.o
*.o.c
*.orig
*.a
*.so
*.dll
*~
.*.sw?
\#*
/META-FAQ
/config.cache
/config.h
/config.log
/config.modules
/config.modules.sh
/config.status
/config.status.lineno
/cscope.out
/stamp-h
/autom4te.cache
Config/defs.mk
CVS
.#*
Doc/help
Doc/help.txt
Doc/help/[_a-zA-Z0-9]*
Doc/intro.pdf
Doc/intro.ps
Doc/intro.a4.pdf
Doc/intro.a4.ps
Doc/intro.us.pdf
Doc/intro.us.ps
Doc/version.yo
Doc/texi2html.conf
Doc/zsh*.1
Doc/zsh.texi
Doc/zsh.info*
Doc/*.html
Doc/zsh.aux
Doc/zsh.toc
Doc/zsh.cp
Doc/zsh.cps
Doc/zsh.fn
Doc/zsh.fns
Doc/zsh.ky
Doc/zsh.kys
Doc/zsh.pg
Doc/zsh.pgs
Doc/zsh.vr
Doc/zsh.vrs
Doc/zsh.log
Doc/zsh.dvi
Doc/zsh_a4.dvi
Doc/zsh_us.dvi
Doc/zsh.tp
Doc/zsh.tps
Doc/zsh.idx
Doc/zsh_*.ps
Doc/infodir
Doc/zsh.pdf
Doc/zsh_a4.pdf
Doc/zsh_us.pdf
Doc/Zsh/modlist.yo
Doc/Zsh/modmenu.yo
Doc/Zsh/manmodmenu.yo
Etc/FAQ
Etc/FAQ.html
Src/*.epro
Src/*.export
Src/*.mdh
Src/*.mdh.tmp
Src/*.mdhi
Src/*.mdhs
Src/*.syms
Src/Makemod.in
Src/Makemod
Src/[_a-zA-Z0-9]*.pro
Src/ansi2knr
Src/bltinmods.list
Src/cscope.out
Src/libzsh.so*
Src/modules-bltin
Src/modules.index
Src/modules.index.tmp
Src/modules.stamp
Src/patchlevel.h
Src/sigcount.h
Src/signames.c
Src/signames2.c
Src/stamp-modobjs
Src/stamp-modobjs.tmp
Src/tags
Src/TAGS
Src/version.h
Src/zsh
Src/zsh.exe
Src/zshcurses.h
Src/zshpaths.h
Src/zshterm.h
Src/zshxmods.h
Src/Builtins/Makefile.in
Src/Builtins/*.export
Src/Builtins/so_locations
Src/Builtins/*.pro
Src/Builtins/*.epro
Src/Builtins/*.syms
Src/Builtins/*.mdh
Src/Builtins/*.mdhi
Src/Builtins/*.mdhs
Src/Builtins/*.mdh.tmp
Src/Builtins/rlimits.h
Src/Modules/Makefile.in
Src/Modules/*.export
Src/Modules/so_locations
Src/Modules/*.pro
Src/Modules/*.epro
Src/Modules/*.syms
Src/Modules/*.mdh
Src/Modules/*.mdhi
Src/Modules/*.mdhs
Src/Modules/*.mdh.tmp
Src/Modules/errnames.c
Src/Modules/errcount.h
Src/Modules/curses_keys.h
Src/Zle/Makefile.in
Src/Zle/*.export
Src/Zle/so_locations
Src/Zle/*.pro
Src/Zle/*.epro
Src/Zle/*.syms
Src/Zle/*.mdh
Src/Zle/*.mdhi
Src/Zle/*.mdhs
Src/Zle/*.mdh.tmp
Src/Zle/thingies.list
Src/Zle/widgets.list
Src/Zle/zle_things.h
Src/Zle/zle_widget.h
Test/*.tmp
/.project

View File

@ -0,0 +1,7 @@
#! /bin/sh
set -e
autoconf
autoheader
echo > stamp-h.in

View File

@ -0,0 +1,2 @@
defs.mk
*.swp

View File

@ -0,0 +1,2 @@
DISTFILES_SRC='
'

View File

@ -0,0 +1,8 @@
AC_DEFUN([zsh_OOT],
[
AC_CHECK_HEADERS(stdarg.h varargs.h termios.h termio.h)
AC_TYPE_SIGNAL
AC_DEFINE([ZSH_OOT_MODULE], [], [Out-of-tree module])
])

View File

@ -0,0 +1,43 @@
#
# Makefile fragment for cleanup
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
mostlyclean: mostlyclean-recursive mostlyclean-here
clean: clean-recursive clean-here
distclean: distclean-recursive distclean-here
realclean: realclean-recursive realclean-here
mostlyclean-here:
clean-here: mostlyclean-here
distclean-here: clean-here
realclean-here: distclean-here
mostlyclean-recursive clean-recursive distclean-recursive realclean-recursive:
@subdirs='$(SUBDIRS)'; if test -n "$$subdirs"; then \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$subdirs; do \
(cd $$subdir && $(MAKE) $(MAKEDEFS) $$target) || exit 1; \
done; \
fi

View File

@ -0,0 +1,42 @@
#
# Makefile fragment for building Makefiles
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
config: Makefile
@subdirs='$(SUBDIRS)'; for subdir in $$subdirs; do \
(cd $$subdir && $(MAKE) $(MAKEDEFS) $@) || exit 1; \
done
CONFIG_INCS = \
$(dir_top)/Config/clean.mk $(dir_top)/Config/config.mk \
$(dir_top)/Config/defs.mk $(dir_top)/Config/version.mk
Makefile: Makefile.in $(dir_top)/config.status $(CONFIG_INCS)
cd $(dir_top) && \
$(SHELL) ./config.status `echo $(subdir)/$@ | sed 's%^./%%'`
$(dir_top)/Config/defs.mk: $(sdir_top)/Config/defs.mk.in $(dir_top)/config.status
cd $(dir_top) && \
$(SHELL) ./config.status Config/defs.mk

View File

@ -0,0 +1,114 @@
#
# Basic Makefile definitions
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
# fundamentals
SHELL = /bin/sh
@SET_MAKE@
EXEEXT = @EXEEXT@
# headers
ZSH_CURSES_H = @ZSH_CURSES_H@
ZSH_TERM_H = @ZSH_TERM_H@
# install basename
tzsh = @tzsh@
# installation directories
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
MODDIR = $(libdir)/$(tzsh)/$(VERSION)
infodir = @infodir@
mandir = @mandir@
datarootdir = @datarootdir@
datadir = @datadir@
fndir = @fndir@
fixed_sitefndir = @fixed_sitefndir@
sitefndir = @sitefndir@
scriptdir = @scriptdir@
sitescriptdir = @sitescriptdir@
htmldir = @htmldir@
runhelpdir = @runhelpdir@
runhelp = @runhelp@
# compilation
CC = @CC@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
DEFS = @DEFS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
EXTRA_LDFLAGS = @EXTRA_LDFLAGS@
DLCFLAGS = @DLCFLAGS@
DLLDFLAGS = @DLLDFLAGS@
LIBLDFLAGS = @LIBLDFLAGS@
EXELDFLAGS = @EXELDFLAGS@
LIBS = @LIBS@
DL_EXT = @DL_EXT@
DLLD = @DLLD@
EXPOPT = @EXPOPT@
IMPOPT = @IMPOPT@
# utilities
AWK = @AWK@
ANSI2KNR = @ANSI2KNR@
YODL = @YODL@ @YODL_OPTIONS@
YODL2TXT = @YODL@2txt
YODL2HTML = @YODL@2html
# install utility
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
# variables used in determining what to install
FUNCTIONS_SUBDIRS = @FUNCTIONS_SUBDIRS@
# Additional fpath entries (eg. for vendor specific directories).
additionalfpath = @additionalfpath@
# flags passed to recursive makes in subdirectories
MAKEDEFS = \
prefix='$(prefix)' exec_prefix='$(exec_prefix)' bindir='$(bindir)' \
libdir='$(libdir)' MODDIR='$(MODDIR)' infodir='$(infodir)' mandir='$(mandir)' \
datadir='$(datadir)' fndir='$(fndir)' htmldir='$(htmldir)' runhelpdir='$(runhelpdir)' \
CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' DEFS='$(DEFS)' CFLAGS='$(CFLAGS)' \
LDFLAGS='$(LDFLAGS)' EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
DLCFLAGS='$(DLCFLAGS)' DLLDFLAGS='$(DLLDFLAGS)' \
LIBLDFLAGS='$(LIBLDFLAGS)' EXELDFLAGS='$(EXELDFLAGS)' \
LIBS='$(LIBS)' DL_EXT='$(DL_EXT)' DLLD='$(DLLD)' \
AWK='$(AWK)' ANSI2KNR='$(ANSI2KNR)' \
YODL='$(YODL)' YODL2TXT='$(YODL2TXT)' YODL2HTML='$(YODL2HTML)' \
FUNCTIONS_INSTALL='$(FUNCTIONS_INSTALL)' tzsh='$(tzsh)'
# override built-in suffix list
.SUFFIXES:
# parallel build is not supported (pmake, gmake)
.NOTPARALLEL:
# parallel build is not supported (dmake)
.NO_PARALLEL:

View File

@ -0,0 +1,74 @@
#!/bin/sh
fndir=$DESTDIR$fndir
scriptdir=$DESTDIR$scriptdir
/bin/sh $sdir_top/mkinstalldirs $fndir || exit 1;
allfuncs="`grep ' functions=.' ${dir_top}/config.modules |
sed -e '/^#/d' -e '/ link=no/d' -e 's/^.* functions=//'`"
allfuncs="`cd $sdir_top; echo ${allfuncs}`"
test -d installfnsdir || mkdir installfnsdir
# We now have a list of files, but we need to use `test -f' to check
# (1) the glob got expanded (2) we are not looking at directories.
for file in $allfuncs; do
if test -f $sdir_top/$file; then
case "$file" in
*/CVS/*) continue;;
esac
if test x$FUNCTIONS_SUBDIRS != x && test x$FUNCTIONS_SUBDIRS != xno; then
case "$file" in
Completion/*/*)
subdir="`echo $file | sed -e 's%/[^/]*/[^/]*$%%'`"
instdir="$fndir/$subdir"
;;
Completion/*)
instdir="$fndir/Completion"
;;
Scripts/*)
instdir="$scriptdir"
;;
*)
subdir="`echo $file | sed -e 's%/[^/]*$%%' -e 's%^Functions/%%'`"
instdir="$fndir/$subdir"
;;
esac
else
case "$file" in
Scripts/*)
instdir="$scriptdir"
;;
*)
instdir="$fndir"
;;
esac
fi
basename=`basename $file`
ok=0
if test -d $instdir || /bin/sh $sdir_top/mkinstalldirs $instdir; then
if sed "s|@runhelpdir@|$runhelpdir|" <$sdir_top/$file \
>installfnsdir/$basename; then
if $INSTALL_DATA installfnsdir/$basename $instdir; then
ok=1
fi
fi
fi
case $ok in
0)
rm -rf installfnsdir
exit 1
;;
esac
read line < $sdir_top/$file
case "$line" in
'#!'*)
chmod +x $instdir/`echo $file | sed -e 's%^.*/%%'`
;;
esac
fi
done
rm -rf installfnsdir

View File

@ -0,0 +1,59 @@
#!/bin/sh
fndir=$DESTDIR$fndir
scriptdir=$DESTDIR$scriptdir
allfuncs="`grep ' functions=' ${dir_top}/config.modules |
sed -e '/^#/d' -e '/ link=no/d' -e 's/^.* functions=//'`"
allfuncs="`cd ${sdir_top}; echo ${allfuncs}`"
case $fndir in
*$VERSION*)
# Version specific function directory, safe to remove completely.
rm -rf $fndir
;;
*) # The following will only apply with a custom install directory
# with no version information. This is rather undesirable.
# But let's try and do the best we can.
# We now have a list of files, but we need to use `test -f' to check
# (1) the glob got expanded (2) we are not looking at directories.
for file in $allfuncs; do
case $file in
Scripts/*)
;;
*)
if test -f $sdir_top/$file; then
if test x$FUNCTIONS_SUBDIRS != x -a x$FUNCTIONS_SUBDIRS != xno; then
file=`echo $file | sed -e 's%%^(Functions|Completion)/%'`
rm -f $fndir/$file
else
bfile="`echo $file | sed -e 's%^.*/%%'`"
rm -f "$fndir/$bfile"
fi
fi
;;
esac
done
;;
esac
case $scriptdir in
*$VERSION*)
# $scriptdir might be the parent of fndir.
rm -rf $scriptdir
;;
*) for file in $allfuncs; do
case $file in
Scripts/*)
if test -f $sdir_top/$file; then
bfile="`echo $file | sed -e 's%^.*/%%'`"
rm -f "$scriptdir/$bfile"
fi
;;
esac
done
;;
esac
exit 0

View File

@ -0,0 +1,31 @@
#
# Makefile fragment for version numbers
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
# This must also serve as a shell script, so do not add spaces around the
# `=' signs.
VERSION=5.3.1-dev-0
VERSION_DATE='December 22, 2016'

View File

@ -0,0 +1,37 @@
Unless otherwise noted in the header of specific files, files in this
distribution have the licence shown below.
However, note that certain shell functions are licensed under versions
of the GNU General Public Licence. Anyone distributing the shell as a
binary including those files needs to take account of this. Search
shell functions for "Copyright" for specific copyright information.
None of the core functions are affected by this, so those files may
simply be omitted.
--
The Z Shell is copyright (c) 1992-2017 Paul Falstad, Richard Coleman,
Zoltán Hidvégi, Andrew Main, Peter Stephenson, Sven Wischnowsky, and
others. All rights reserved. Individual authors, whether or not
specifically named, retain copyright in all changes; in what follows, they
are referred to as `the Zsh Development Group'. This is for convenience
only and this body has no legal status. The Z shell is distributed under
the following licence; any provisions made in individual files take
precedence.
Permission is hereby granted, without written agreement and without
licence or royalty fees, to use, copy, modify, and distribute this
software and to distribute modified versions of this software for any
purpose, provided that the above copyright notice and the following
two paragraphs appear in all copies of this software.
In no event shall the Zsh Development Group be liable to any party for
direct, indirect, special, incidental, or consequential damages arising out
of the use of this software and its documentation, even if the Zsh
Development Group have been advised of the possibility of such damage.
The Zsh Development Group specifically disclaim any warranties, including,
but not limited to, the implied warranties of merchantability and fitness
for a particular purpose. The software provided hereunder is on an "as is"
basis, and the Zsh Development Group have no obligation to provide
maintenance, support, updates, enhancements, or modifications.

View File

@ -0,0 +1,87 @@
#
# Makefile for top level of zsh distribution
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
subdir = .
dir_top = .
SUBDIRS = Src
@VERSION_MK@
# source/build directories
VPATH = @srcdir@
sdir = @srcdir@
sdir_top = @top_srcdir@
INSTALL = @INSTALL@
@DEFS_MK@
# ========== DEPENDENCIES FOR BUILDING ==========
# default target
all: config.h config.modules
cd Src && $(MAKE) $(MAKEDEFS) $@
# prepare module configuration
prep:
@cd Src && $(MAKE) $(MAKEDEFS) $@
# ========== DEPENDENCIES FOR CLEANUP ==========
@CLEAN_MK@
distclean-here:
rm -f Makefile config.h config.status config.log config.cache config.modules config.modules.sh stamp-h Config/defs.mk
rm -rf autom4te.cache
realclean-here:
cd $(sdir) && rm -f config.h.in stamp-h.in configure
# ========== DEPENDENCIES FOR MAINTENANCE ==========
@CONFIG_MK@
config: config.h
config.status: $(sdir)/configure
$(SHELL) ./config.status --recheck
$(sdir)/configure: $(sdir)/aclocal.m4 $(sdir)/aczsh.m4 $(sdir)/configure.ac
cd $(sdir) && autoconf
config.h: stamp-h
stamp-h: $(sdir)/config.h.in config.status
cd $(dir_top) && $(SHELL) ./config.status config.h $@
config.modules: $(sdir)/config.h.in config.status config.modules.sh
cd $(dir_top) && $(SHELL) ./config.status $@ && \
$(SHELL) ./config.modules.sh
$(sdir)/config.h.in: $(sdir)/stamp-h.in
$(sdir)/stamp-h.in: $(sdir)/configure
cd $(sdir) && autoheader
echo > $(sdir)/stamp-h.in
FORCE:

View File

@ -0,0 +1 @@
1580588806

View File

@ -0,0 +1,35 @@
*.dll
*.epro
*.export
*.mdh
*.mdh.tmp
*.mdhi
*.mdhs
*.o
*.o.c
*.so
*.swp
*.syms
Makefile
Makemod.in Makemod
[_a-zA-Z0-9]*.pro
ansi2knr
bltinmods.list
cscope.out
libzsh.so*
modules-bltin
modules.index
modules.index.tmp
modules.stamp
patchlevel.h
sigcount.h
signames.c signames2.c
stamp-modobjs
stamp-modobjs.tmp
tags TAGS
version.h
zsh
zshcurses.h
zshpaths.h
zshterm.h
zshxmods.h

View File

@ -0,0 +1,2 @@
DISTFILES_SRC='
'

View File

@ -0,0 +1,2 @@
set ai
set sw=4

View File

@ -0,0 +1,27 @@
--dont-format-comments
--procnames-start-lines
--no-parameter-indentation
--indent-level4
--line-comments-indentation4
--cuddle-else
--brace-indent0
--dont-star-comments
--blank-lines-after-declarations
--blank-lines-after-procedures
--no-blank-lines-after-commas
--comment-indentation33
--declaration-comment-column33
--no-comment-delimiters-on-blank-lines
--continuation-indentation4
--case-indentation0
--else-endif-column33
--no-space-after-casts
--no-blank-before-sizeof
--declaration-indentation0
--continue-at-parentheses
--no-space-after-function-call-names
--swallow-optional-blank-lines
--dont-space-special-semicolon
--tab-size8
--line-length132
--braces-on-if-line

View File

@ -0,0 +1,164 @@
#
# Makefile for Src subdirectory
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
subdir = Src
dir_top = ..
SUBDIRS =
@VERSION_MK@
# source/build directories
VPATH = @srcdir@
sdir = @srcdir@
sdir_top = @top_srcdir@
INSTALL = @INSTALL@
LN = @LN@
@DEFS_MK@
sdir_src = $(sdir)
dir_src = .
# ========= DEPENDENCIES FOR BUILDING ==========
LINK = $(CC) $(LDFLAGS) $(EXELDFLAGS) $(EXTRA_LDFLAGS) -o $@
DLLINK = $(DLLD) $(LDFLAGS) $(LIBLDFLAGS) $(DLLDFLAGS) -o $@
all: zsh.export modules
.PHONY: all
modules: headers
.PHONY: modules
L = @L@
LSTMP =
LLIST =
NSTMP = stamp-modobjs
NLIST = `cat stamp-modobjs`
LIBZSH = libzsh-$(VERSION).$(DL_EXT)
NIBZSH =
INSTLIB = @INSTLIB@
UNINSTLIB = @UNINSTLIB@
ZSH_EXPORT = $(EXPOPT)zsh.export
ZSH_NXPORT =
ENTRYOBJ = modentry..o
NNTRYOBJ =
LDRUNPATH = LD_RUN_PATH=$(libdir)/$(tzsh)
NDRUNPATH =
EXTRAZSHOBJS = @EXTRAZSHOBJS@
stamp-modobjs: modobjs
@if cmp -s stamp-modobjs.tmp stamp-modobjs; then \
rm -f stamp-modobjs.tmp; \
echo "\`stamp-modobjs' is up to date."; \
else \
mv -f stamp-modobjs.tmp stamp-modobjs; \
echo "Updated \`stamp-modobjs'."; \
fi
modobjs: headers rm-modobjs-tmp
.PHONY: modobjs
rm-modobjs-tmp:
rm -f stamp-modobjs.tmp
.PHONY: rm-modobjs-tmp
@CONFIG_MK@
Makemod: $(CONFIG_INCS) $(dir_top)/config.modules
@case $(sdir_top) in \
/*) top_srcdir=$(sdir_top) ;; \
*) top_srcdir=$(subdir)/$(sdir_top) ;; \
esac; \
export top_srcdir; \
echo 'cd $(dir_top) && $(SHELL)' \
'$$top_srcdir/$(subdir)/mkmakemod.sh $(subdir) Makemod'; \
cd $(dir_top) && \
$(SHELL) $$top_srcdir/$(subdir)/mkmakemod.sh $(subdir) Makemod
prep: Makemod
@$(MAKE) -f Makemod $(MAKEDEFS) prep || rm -f Makemod
.PHONY: prep
FORCE:
.PHONY: FORCE
# ========== LINKING IN MODULES ==========
mymods.conf:
@echo Linking with the standard modules.
modules: $(@E@NTRYOBJ)
$(ENTRYOBJ): FORCE
@$(MAKE) -f Makemod $(MAKEDEFS) $@
# ========== DEPENDENCIES FOR CLEANUP ==========
# Since module cleanup rules depend on Makemod, they come first. This
# forces module stuff to get cleaned before Makemod itself gets
# deleted.
mostlyclean-here:
rm -f stamp-modobjs stamp-modobjs.tmp
.PHONY: mostlyclean-here
clean-here:
rm -f modules.stamp zsh$(EXEEXT)
rm -f libzsh-*.$(DL_EXT)
.PHONY: clean-here
distclean-here:
rm -f TAGS tags
rm -f Makefile
.PHONY: distclean-here
mostlyclean: mostlyclean-modules
clean: clean-modules
distclean: distclean-modules
realclean: realclean-modules
.PHONY: mostlyclean clean distclean realclean
# Don't remake Makemod just to delete things, even if it doesn't exist.
mostlyclean-modules clean-modules distclean-modules realclean-modules:
if test -f Makemod; then \
$(MAKE) -f Makemod $(MAKEDEFS) `echo $@ | sed 's/-modules//'`; \
fi; \
exit 0
.PHONY: mostlyclean-modules clean-modules distclean-modules \
realclean-modules
@CLEAN_MK@
# ========== RECURSIVE MAKES ==========
modobjs modules headers proto zsh.export: Makemod
@$(MAKE) -f Makemod $(MAKEDEFS) $@
.PHONY: headers proto

View File

@ -0,0 +1,192 @@
#
# Makemod.in.in
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
# ========== OVERRIDABLE VARIABLES ==========
# subdir is done by mkmakemod.sh
# dir_top is done by mkmakemod.sh
# SUBDIRS is done by mkmakemod.sh
@VERSION_MK@
# source/build directories
VPATH = @srcdir@
sdir = @srcdir@
sdir_top = @top_srcdir@
INSTALL = @INSTALL@
@DEFS_MK@
sdir_src = $(sdir_top)/Src
dir_src = $(dir_top)/Src
# ========== COMPILATION RULES ==========
DNCFLAGS =
COMPILE = $(CC) -c -I. -I$(dir_top)/Src -I$(sdir_top)/Src -I$(sdir_top)/Src/Zle -I$(sdir) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(D@L@CFLAGS)
DLCOMPILE = $(CC) -c -I. -I$(dir_top)/Src -I$(sdir_top)/Src -I$(sdir_top)/Src/Zle -I$(sdir) $(CPPFLAGS) $(DEFS) -DMODULE $(CFLAGS) $(DLCFLAGS)
LINK = $(CC) $(LDFLAGS) $(EXELDFLAGS) $(EXTRA_LDFLAGS) -o $@
DLLINK = $(DLLD) $(LDFLAGS) $(LIBLDFLAGS) $(DLLDFLAGS) -o $@
KNR_OBJ=.o
KNROBJ=._foo_
ANSIOBJ=.o
ANSI_OBJ=._foo_
.SUFFIXES: .c .$(DL_EXT) ..o .._foo_ .o ._foo_ .syms .pro .epro
.c$(ANSI@U@OBJ):
$(COMPILE) -o $@ $<
@rm -f $(dir_src)/stamp-modobjs
.c$(KNR@U@OBJ):
@ANSI2KNR@ $< > $@.c
$(COMPILE) -o $@ $@.c
rm -f $@.c
@rm -f $(dir_src)/stamp-modobjs
.c.$(ANSI@U@OBJ):
$(DLCOMPILE) -o $@ $<
.c.$(KNR@U@OBJ):
@ANSI2KNR@ $< > $@.c
$(DLCOMPILE) -o $@ $@.c
rm -f $@.c
.c.syms:
$(AWK) -f $(sdir_src)/makepro.awk $< $(subdir) > $@
.syms.epro:
(echo '/* Generated automatically */'; sed -n '/^E/{s/^E//;p;}' < $<) \
> $@
(echo '/* Generated automatically */'; sed -n '/^L/{s/^L//;p;}' < $<) \
> `echo $@ | sed 's/\.epro$$/.pro/'`
PROTODEPS = $(sdir_src)/makepro.awk
# ========== DEPENDENCIES FOR BUILDING ==========
all: modobjs modules
.PHONY: all
modobjs: $(MODOBJS)
modules: $(MODULES)
headers: $(MDHS)
proto: $(PROTOS)
.PHONY: modobjs modules headers proto
prep:
@case $(sdir_top) in \
/*) top_srcdir=$(sdir_top) ;; \
*) top_srcdir=$(subdir)/$(sdir_top) ;; \
esac; \
export top_srcdir; \
cd $(dir_top) || exit 1; \
subdirs='$(SUBDIRS)'; \
for subdir in $$subdirs; do \
dir=$(subdir)/$$subdir; \
test -d $$dir || mkdir $$dir; \
$(SHELL) $$top_srcdir/Src/mkmakemod.sh $$dir Makefile || exit 1; \
( cd $$dir && $(MAKE) $(MAKEDEFS) $@ ) || exit 1; \
done
.PHONY: prep
headers: $(dir_src)/modules.stamp
$(dir_src)/modules.stamp: $(MDDS)
$(MAKE) -f $(makefile) $(MAKEDEFS) prep
echo 'timestamp for *.mdd files' > $@
.PHONY: headers
FORCE:
.PHONY: FORCE
# ========== DEPENDENCIES FOR INSTALLING ==========
install: install.bin install.modules
uninstall: uninstall.bin uninstall.modules
.PHONY: install uninstall
install.bin: install.bin-here
uninstall.bin: uninstall.bin-here
install.modules: install.modules-here
uninstall.modules: uninstall.modules-here
.PHONY: install.bin uninstall.bin install.modules uninstall.modules
install.bin-here uninstall.bin-here:
install.modules-here uninstall.modules-here:
.PHONY: install.bin-here install.modules-here
# ========== DEPENDENCIES FOR CLEANUP ==========
@CLEAN_MK@
mostlyclean-here:
rm -f *.o *.export *.$(DL_EXT)
.PHONY: mostlyclean-here
clean-here:
rm -f *.o.c *.syms *.pro *.epro *.mdh *.mdhi *.mdhs *.mdh.tmp
.PHONY: clean-here
distclean-here:
rm -f $(makefile) $(makefile).in
.PHONY: distclean-here
# ========== RECURSIVE MAKES ==========
install.bin uninstall.bin install.modules uninstall.modules \
modobjs modules headers proto:
@subdirs='$(SUBDIRS)'; for subdir in $$subdirs; do \
( cd $$subdir && $(MAKE) $(MAKEDEFS) $@ ) || exit 1; \
done
# ========== DEPENDENCIES FOR MAINTENANCE ==========
$(makefile): $(makefile).in $(dir_top)/config.status
@case $(sdir_top) in \
/*) top_srcdir=$(sdir_top) ;; \
*) top_srcdir=$(subdir)/$(sdir_top) ;; \
esac; \
export top_srcdir; \
echo 'cd $(dir_top) && $(SHELL)' \
'$$top_srcdir/Src/mkmakemod.sh -m $(subdir) $(makefile)'; \
cd $(dir_top) && \
$(SHELL) $$top_srcdir/Src/mkmakemod.sh -m $(subdir) $(makefile)
$(makefile).in: $(sdir_src)/mkmakemod.sh $(sdir_src)/Makemod.in.in $(MDDS) \
$(dir_top)/config.modules
@case $(sdir_top) in \
/*) top_srcdir=$(sdir_top) ;; \
*) top_srcdir=$(subdir)/$(sdir_top) ;; \
esac; \
export top_srcdir; \
echo 'cd $(dir_top) && $(SHELL)' \
'$$top_srcdir/Src/mkmakemod.sh -i $(subdir) $(makefile)'; \
cd $(dir_top) && \
$(SHELL) $$top_srcdir/Src/mkmakemod.sh -i $(subdir) $(makefile)

View File

@ -0,0 +1,18 @@
Makefile
Makefile.in
*.export
so_locations
*.pro
*.epro
*.syms
*.o
*.o.c
*.so
*.mdh
*.mdhi
*.mdhs
*.mdh.tmp
*.swp
errnames.c errcount.h
*.dll
curses_keys.h

View File

@ -0,0 +1,2 @@
DISTFILES_SRC='
'

View File

@ -0,0 +1,2 @@
set ai
set sw=4

View File

@ -0,0 +1,8 @@
Makefile.in
*.epro
*.export
*.mdh
*.mdhi
*.mdhs
*.pro
*.syms

View File

@ -0,0 +1,543 @@
#include "fzftab.mdh"
#include "fzftab.pro"
#include <stdarg.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
const char* get_color(char* file, const struct stat* sb);
const char* get_suffix(char* file, const struct stat* sb);
const char* colorize_from_mode(char* file, const struct stat* sb);
const char* colorize_from_name(char* file);
char** fzf_tab_colorize(char* file);
int compile_patterns(char* nam, char** list_colors);
char* ftb_strcat(char* dst, int n, ...);
/* Indixes into the terminal string arrays. */
#define COL_NO 0
#define COL_FI 1
#define COL_DI 2
#define COL_LN 3
#define COL_PI 4
#define COL_SO 5
#define COL_BD 6
#define COL_CD 7
#define COL_OR 8
#define COL_MI 9
#define COL_SU 10
#define COL_SG 11
#define COL_TW 12
#define COL_OW 13
#define COL_ST 14
#define COL_EX 15
#define COL_LC 16
#define COL_RC 17
#define COL_EC 18
#define COL_TC 19
#define COL_SP 20
#define COL_MA 21
#define COL_HI 22
#define COL_DU 23
#define COL_SA 24
#define NUM_COLS 25
/* Names of the terminal strings. */
static char* colnames[] = { "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "or", "mi", "su", "sg",
"tw", "ow", "st", "ex", "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", "sa", NULL };
/* Default values. */
static char* defcols[]
= { "0", "0", "1;31", "1;36", "33", "1;35", "1;33", "1;33", NULL, NULL, "37;41", "30;43",
"30;42", "34;42", "37;44", "1;32", "\033[", "m", NULL, "0", "0", "7", NULL, NULL, "0" };
static char* fzf_tab_module_version;
struct pattern {
Patprog pat;
char color[50];
};
static int opt_list_type = OPT_INVALID;
static int pat_cnt = 0;
static struct pattern* name_color = NULL;
static char mode_color[NUM_COLS][20];
// TODO: use ZLS_COLORS ?
int compile_patterns(char* nam, char** list_colors)
{
// clean old name_color and set pat_cnt = 0
if (pat_cnt != 0) {
while (--pat_cnt) {
freepatprog(name_color[pat_cnt].pat);
}
free(name_color);
}
// initialize mode_color with default value
for (int i = 0; i < NUM_COLS; i++) {
if (defcols[i]) {
strcpy(mode_color[i], defcols[i]);
}
}
// empty array, just return
if (list_colors == NULL) {
return 0;
}
// how many pattens?
while (list_colors[pat_cnt] != NULL) {
pat_cnt++;
}
name_color = zshcalloc(pat_cnt * sizeof(struct pattern));
for (int i = 0; i < pat_cnt; i++) {
char* pat = ztrdup(list_colors[i]);
char* color = strrchr(pat, '=');
if (color == NULL)
continue;
*color = '\0';
tokenize(pat);
remnulargs(pat);
// mode=color
bool skip = false;
for (int j = 0; j < NUM_COLS; j++) {
if (strpfx(colnames[j], list_colors[i])) {
strcpy(mode_color[j], color + 1);
name_color[i].pat = NULL;
skip = true;
}
}
if (skip) {
continue;
}
// name=color
if (!(name_color[i].pat = patcompile(pat, PAT_ZDUP, NULL))) {
zwarnnam(nam, "bad pattern: %s", list_colors[i]);
return 1;
}
strcpy(name_color[i].color, color + 1);
free(pat);
}
return 0;
}
// TODO: use zsh mod_export function `file_type` ?
const char* get_suffix(char* file, const struct stat* sb)
{
struct stat sb2;
mode_t filemode = sb->st_mode;
if (S_ISBLK(filemode))
return "#";
else if (S_ISCHR(filemode))
return "%";
else if (S_ISDIR(filemode))
return "/";
else if (S_ISFIFO(filemode))
return "|";
else if (S_ISLNK(filemode))
if (strpfx(mode_color[COL_LN], "target")) {
if (stat(file, &sb2) == -1) {
return "@";
}
return get_suffix(file, &sb2);
} else {
return "@";
}
else if (S_ISREG(filemode))
return (filemode & S_IXUGO) ? "*" : "";
else if (S_ISSOCK(filemode))
return "=";
else
return "?";
}
const char* get_color(char* file, const struct stat* sb)
{
// no list-colors, return empty color
if (pat_cnt == 0) {
return "";
}
const char* ret;
if ((ret = colorize_from_mode(file, sb)) || (ret = colorize_from_name(file))) {
return ret;
}
return mode_color[COL_FI];
}
const char* colorize_from_name(char* file)
{
for (int i = 0; i < pat_cnt; i++) {
if (name_color && name_color[i].pat && pattry(name_color[i].pat, file)) {
return name_color[i].color;
}
}
return NULL;
}
const char* colorize_from_mode(char* file, const struct stat* sb)
{
struct stat sb2;
switch (sb->st_mode & S_IFMT) {
case S_IFDIR:
return mode_color[COL_DI];
case S_IFLNK: {
if (strpfx(mode_color[COL_LN], "target")) {
if (stat(file, &sb2) == -1) {
return mode_color[COL_OR];
}
return get_color(file, &sb2);
}
}
case S_IFIFO:
return mode_color[COL_PI];
case S_IFSOCK:
return mode_color[COL_SO];
case S_IFBLK:
return mode_color[COL_BD];
case S_IFCHR:
return mode_color[COL_CD];
default:
break;
}
if (sb->st_mode & S_ISUID) {
return mode_color[COL_SU];
} else if (sb->st_mode & S_ISGID) {
return mode_color[COL_SG];
// tw ow st ??
} else if (sb->st_mode & S_IXUSR) {
return mode_color[COL_EX];
}
/* Check for suffix alias */
size_t len = strlen(file);
/* shortest valid suffix format is a.b */
if (len > 2) {
const char* suf = file + len - 1;
while (suf > file + 1) {
if (suf[-1] == '.') {
if (sufaliastab->getnode(sufaliastab, suf)) {
return mode_color[COL_SA];
}
break;
}
suf--;
}
}
return NULL;
}
struct {
char** array;
size_t len;
size_t size;
} ftb_compcap;
// Usage:
// initialize fzf-tab-generate-compcap -i
// output to _ftb_compcap fzf-tab-generate-compcap -o
// add a entry fzf-tab-generate-compcap word desc opts
static int bin_fzf_tab_compcap_generate(char* nam, char** args, Options ops, UNUSED(int func))
{
if (OPT_ISSET(ops, 'o')) {
// write final result to _ftb_compcap
setaparam("_ftb_compcap", ftb_compcap.array);
ftb_compcap.array = NULL;
return 0;
} else if (OPT_ISSET(ops, 'i')) {
// init
if (ftb_compcap.array)
freearray(ftb_compcap.array);
ftb_compcap.array = zshcalloc(1024 * sizeof(char*));
ftb_compcap.len = 0, ftb_compcap.size = 1024;
return 0;
}
if (ftb_compcap.array == NULL) {
zwarnnam(nam, "please initialize it first");
return 1;
}
// get paramaters
char **words = getaparam(args[0]), **dscrs = getaparam(args[1]), *opts = getsparam(args[2]);
if (!words || !dscrs || !opts) {
zwarnnam(nam, "wrong argument");
return 1;
}
char *bs = metafy("\2", 1, META_DUP), *nul = metafy("\0word\0", 6, META_DUP);
size_t dscrs_cnt = arrlen(dscrs);
for (int i = 0; words[i]; i++) {
// TODO: replace '\n'
char* buffer = zshcalloc(256 * sizeof(char));
char* dscr = i < dscrs_cnt ? dscrs[i] : words[i];
buffer = ftb_strcat(buffer, 5, dscr, bs, opts, nul, words[i]);
ftb_compcap.array[ftb_compcap.len++] = buffer;
if (ftb_compcap.len == ftb_compcap.size) {
ftb_compcap.array
= zrealloc(ftb_compcap.array, (1024 + ftb_compcap.size) * sizeof(char*));
ftb_compcap.size += 1024;
memset(ftb_compcap.array + ftb_compcap.size - 1024, 0, 1024 * sizeof(char*));
}
}
zsfree(bs);
zsfree(nul);
return 0;
}
// cat n string, return the pointer to the new string
// `size` is the size of dst
// dst will be reallocated if is not big enough
char* ftb_strcat(char* dst, int n, ...)
{
va_list valist;
va_start(valist, n);
char* final = zrealloc(dst, 128);
size_t size = 128, max_len = 128 - 1;
dst = final;
for (int i = 0, idx = 0; i < n; i++) {
char* src = va_arg(valist, char*);
for (; *src != '\0'; dst++, src++, idx++) {
if (idx == max_len) {
size += size / 2;
final = zrealloc(final, size);
max_len = size - 1;
dst = &final[idx];
}
*dst = *src;
}
}
*dst = '\0';
va_end(valist);
return final;
}
// accept an
char** fzf_tab_colorize(char* file)
{
// TODO: can avoid so many zalloc here?
file = unmeta(file);
struct stat sb;
if (lstat(file, &sb) == -1) {
return NULL;
}
const char* suffix = "";
if (isset(opt_list_type)) {
suffix = get_suffix(file, &sb);
}
const char* color = get_color(file, &sb);
char* symlink = "";
const char* symcolor = "";
if ((sb.st_mode & S_IFMT) == S_IFLNK) {
symlink = zalloc(PATH_MAX);
int end = readlink(file, symlink, PATH_MAX);
symlink[end] = '\0';
if (stat(file, &sb) == -1) {
symcolor = mode_color[COL_OR];
} else {
char tmp[PATH_MAX];
realpath(file, tmp);
symcolor = get_color(file, &sb);
}
}
char** reply = zshcalloc((4 + 1) * sizeof(char*));
if (strlen(color) != 0) {
reply[0] = zalloc(128);
reply[1] = zalloc(128);
sprintf(reply[0], "%s%s%s", mode_color[COL_LC], color, mode_color[COL_RC]);
sprintf(reply[1], "%s%s%s", mode_color[COL_LC], "0", mode_color[COL_RC]);
} else {
reply[0] = ztrdup("");
reply[1] = ztrdup("");
}
reply[2] = ztrdup(suffix);
if (symlink[0] != '\0') {
reply[3] = zalloc(PATH_MAX);
sprintf(reply[3], "%s%s%s%s%s%s%s", mode_color[COL_LC], symcolor, mode_color[COL_RC],
symlink, mode_color[COL_LC], "0", mode_color[COL_RC]);
free(symlink);
} else {
reply[3] = ztrdup("");
}
for (int i = 0; i < 4; i++) {
reply[i] = metafy(reply[i], -1, META_REALLOC);
}
return reply;
}
static int bin_fzf_tab_candidates_generate(char* nam, char** args, Options ops, UNUSED(int func))
{
if (OPT_ISSET(ops, 'i')) {
// compile list_colors pattern
if (*args == NULL) {
zwarnnam(nam, "please specify an array");
return 1;
} else {
char** array = getaparam(*args);
return compile_patterns(nam, array);
}
}
char **ftb_compcap = getaparam("_ftb_compcap"), **group_colors = getaparam("group_colors"),
*default_color = getsparam("default_color"), *prefix = getsparam("prefix");
size_t group_colors_len = arrlen(group_colors);
size_t ftb_compcap_len = arrlen(ftb_compcap);
char *bs = metafy("\b", 1, META_DUP), *nul = metafy("\0", 1, META_DUP),
*soh = metafy("\2", 1, META_DUP);
char **candidates = zshcalloc(sizeof(char*) * (ftb_compcap_len + 1)),
*filepath = zshcalloc(PATH_MAX * sizeof(char)), *dpre = zshcalloc(128),
*dsuf = zshcalloc(128);
char* first_word = zshcalloc(512 * sizeof(char));
int same_word = 1;
for (int i = 0; i < ftb_compcap_len; i++) {
char *word = "", *group = NULL, *realdir = NULL;
strcpy(dpre, "");
strcpy(dsuf, "");
// extract all the variables what we need
char** compcap = sepsplit(ftb_compcap[i], soh, 1, 0);
char* desc = compcap[0];
char** info = sepsplit(compcap[1], nul, 1, 0);
for (int j = 0; info[j]; j += 2) {
if (!strcmp(info[j], "word")) {
word = info[j + 1];
// unquote word
parse_subst_string(word);
remnulargs(word);
untokenize(word);
} else if (!strcmp(info[j], "group")) {
group = info[j + 1];
} else if (!strcmp(info[j], "realdir")) {
realdir = info[j + 1];
}
}
// check if all the words are the same
if (i == 0) {
first_word = ftb_strcat(first_word, 1, word);
} else if (same_word && strcmp(word, first_word) != 0) {
same_word = 0;
}
// add character and color to describe the type of the files
if (realdir) {
filepath = ftb_strcat(filepath, 2, realdir, word);
char** reply = fzf_tab_colorize(filepath);
if (reply != NULL) {
dpre = ftb_strcat(dpre, 2, reply[1], reply[0]);
if (reply[3][0] != '\0') {
dsuf = ftb_strcat(dsuf, 4, reply[1], reply[2], " -> ", reply[3]);
} else {
dsuf = ftb_strcat(dsuf, 2, reply[1], reply[2]);
}
if (dpre[0] != '\0') {
setiparam("colorful", 1);
}
freearray(reply);
}
}
char* result = zshcalloc(256 * sizeof(char));
// add color to description if they have group index
if (group) {
// use strtol ?
int group_index = atoi(group);
char* color = group_index >= group_colors_len ? "" : group_colors[group_index - 1];
// add prefix
result = ftb_strcat(
result, 11, group, bs, color, prefix, dpre, nul, group, bs, desc, nul, dsuf);
} else {
result = ftb_strcat(result, 6, default_color, dpre, nul, desc, nul, dsuf);
}
// quotedzputs(result, stdout);
// putchar('\n');
candidates[i] = result;
freearray(info);
freearray(compcap);
}
setaparam("tcandidates", candidates);
setiparam("same_word", same_word);
zsfree(dpre);
zsfree(dsuf);
zsfree(filepath);
zsfree(first_word);
return 0;
}
static struct builtin bintab[] = {
BUILTIN("fzf-tab-compcap-generate", 0, bin_fzf_tab_compcap_generate, 0, -1, 0, "io", NULL),
BUILTIN("fzf-tab-candidates-generate", 0, bin_fzf_tab_candidates_generate, 0, -1, 0, "i", NULL),
};
static struct paramdef patab[] = {
STRPARAMDEF("FZF_TAB_MODULE_VERSION", &fzf_tab_module_version),
};
// clang-format off
static struct features module_features = {
bintab, sizeof(bintab) / sizeof(*bintab),
NULL, 0,
NULL, 0,
patab, sizeof(patab) / sizeof(*patab),
0,
};
// clang-format on
int setup_(UNUSED(Module m)) { return 0; }
int features_(Module m, char*** features)
{
*features = featuresarray(m, &module_features);
return 0;
}
int enables_(Module m, int** enables) { return handlefeatures(m, &module_features, enables); }
int boot_(UNUSED(Module m))
{
fzf_tab_module_version = ztrdup("0.2.2");
// different zsh version may have different value of list_type's index
// so query it dynamically
opt_list_type = optlookup("list_types");
return 0;
}
int cleanup_(UNUSED(Module m)) { return setfeatureenables(m, &module_features, NULL); }
int finish_(UNUSED(Module m))
{
printf("fzf-tab module unloaded.\n");
fflush(stdout);
return 0;
}

View File

@ -0,0 +1,7 @@
name=aloxaf/fzftab
link=dynamic
load=no
autofeatures="b:fzf-tab-colorize p:FZF_TAB_MODULE_VERSION"
objects="fzftab.o"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,742 @@
/*
* compat.c - compatibility routines for the deprived
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1997 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#include "zsh.mdh"
#include "compat.pro"
/* Return pointer to first occurence of string t *
* in string s. Return NULL if not present. */
/**/
#ifndef HAVE_STRSTR
/**/
char *
strstr(const char *s, const char *t)
{
const char *p1, *p2;
for (; *s; s++) {
for (p1 = s, p2 = t; *p2; p1++, p2++)
if (*p1 != *p2)
break;
if (!*p2)
return (char *)s;
}
return NULL;
}
/**/
#endif
/**/
#ifndef HAVE_GETHOSTNAME
/**/
int
gethostname(char *name, size_t namelen)
{
struct utsname uts;
uname(&uts);
if(strlen(uts.nodename) >= namelen) {
errno = EINVAL;
return -1;
}
strcpy(name, uts.nodename);
return 0;
}
/**/
#endif
/**/
#ifndef HAVE_GETTIMEOFDAY
/**/
int
gettimeofday(struct timeval *tv, struct timezone *tz)
{
tv->tv_usec = 0;
tv->tv_sec = (long)time((time_t) 0);
return 0;
}
/**/
#endif
/* Provide clock time with nanoseconds */
/**/
mod_export int
zgettime(struct timespec *ts)
{
int ret = -1;
#ifdef HAVE_CLOCK_GETTIME
struct timespec dts;
if (clock_gettime(CLOCK_REALTIME, &dts) < 0) {
zwarn("unable to retrieve time: %e", errno);
ret--;
} else {
ret++;
ts->tv_sec = (time_t) dts.tv_sec;
ts->tv_nsec = (long) dts.tv_nsec;
}
#endif
if (ret) {
struct timeval dtv;
struct timezone dtz;
gettimeofday(&dtv, &dtz);
ret++;
ts->tv_sec = (time_t) dtv.tv_sec;
ts->tv_nsec = (long) dtv.tv_usec * 1000;
}
return ret;
}
/* compute the difference between two calendar times */
/**/
#ifndef HAVE_DIFFTIME
/**/
double
difftime(time_t t2, time_t t1)
{
return ((double)t2 - (double)t1);
}
/**/
#endif
/**/
#ifndef HAVE_STRERROR
extern char *sys_errlist[];
/* Get error message string associated with a particular *
* error number, and returns a pointer to that string. *
* This is not a particularly robust version of strerror. */
/**/
char *
strerror(int errnum)
{
return (sys_errlist[errnum]);
}
/**/
#endif
#if 0
/* pathconf(_PC_PATH_MAX) is not currently useful to zsh. The value *
* returned varies depending on a number of factors, e.g. the amount *
* of memory available to the operating system at a given time; thus *
* it can't be used for buffer allocation, or even as an indication *
* of whether an attempt to use or create a given pathname may fail *
* at any future time. *
* *
* The call is also permitted to fail if the argument path is not an *
* existing directory, so even to make sense of that one must search *
* for a valid directory somewhere in the path and adjust. Even if *
* it succeeds, the return value is relative to the input directory, *
* and therefore potentially relative to the length of the shortest *
* path either to that directory or to our working directory. *
* *
* Finally, see the note below for glibc; detection of pathconf() is *
* not by itself an indication that it works reliably. */
/* The documentation for pathconf() says something like: *
* The limit is returned, if one exists. If the system does *
* not have a limit for the requested resource, -1 is *
* returned, and errno is unchanged. If there is an error, *
* -1 is returned, and errno is set to reflect the nature of *
* the error. *
* *
* System calls are not permitted to set errno to 0; but we must (or *
* some other flag value) in order to determine that the resource is *
* unlimited. What use is leaving errno unchanged? Instead, define *
* a wrapper that resets errno to 0 and returns 0 for "the system *
* does not have a limit," so that -1 always means a real error. */
/**/
mod_export long
zpathmax(char *dir)
{
#ifdef HAVE_PATHCONF
long pathmax;
errno = 0;
if ((pathmax = pathconf(dir, _PC_PATH_MAX)) >= 0) {
/* Some versions of glibc pathconf return a hardwired value! */
return pathmax;
} else if (errno == EINVAL || errno == ENOENT || errno == ENOTDIR) {
/* Work backward to find a directory, until we run out of path. */
char *tail = strrchr(dir, '/');
while (tail > dir && tail[-1] == '/')
--tail;
if (tail > dir) {
*tail = 0;
pathmax = zpathmax(dir);
*tail = '/';
} else {
errno = 0;
if (tail)
pathmax = pathconf("/", _PC_PATH_MAX);
else
pathmax = pathconf(".", _PC_PATH_MAX);
}
if (pathmax > 0) {
long taillen = (tail ? strlen(tail) : (strlen(dir) + 1));
if (taillen < pathmax)
return pathmax - taillen;
else
errno = ENAMETOOLONG;
}
}
if (errno)
return -1;
else
return 0; /* pathmax should be considered unlimited */
#else
long dirlen = strlen(dir);
/* The following is wrong if dir is not an absolute path. */
return ((long) ((dirlen >= PATH_MAX) ?
((errno = ENAMETOOLONG), -1) :
((errno = 0), PATH_MAX - dirlen)));
#endif
}
#endif /* 0 */
/**/
#ifdef HAVE_SYSCONF
/*
* This is replaced by a macro from system.h if not HAVE_SYSCONF.
* 0 is returned by sysconf if _SC_OPEN_MAX is unavailable;
* -1 is returned on error
*
* Neither of these should happen, but resort to OPEN_MAX rather
* than return 0 or -1 just in case.
*
* We'll limit the open maximum to ZSH_INITIAL_OPEN_MAX to
* avoid probing ridiculous numbers of file descriptors.
*/
/**/
mod_export long
zopenmax(void)
{
long openmax;
if ((openmax = sysconf(_SC_OPEN_MAX)) < 1) {
openmax = OPEN_MAX;
} else if (openmax > OPEN_MAX) {
/* On some systems, "limit descriptors unlimited" or the *
* equivalent will set openmax to a huge number. Unless *
* there actually is a file descriptor > OPEN_MAX already *
* open, nothing in zsh requires the true maximum, and in *
* fact it causes inefficiency elsewhere if we report it. *
* So, report the maximum of OPEN_MAX or the largest open *
* descriptor (is there a better way to find that?). */
long i, j = OPEN_MAX;
if (openmax > ZSH_INITIAL_OPEN_MAX)
openmax = ZSH_INITIAL_OPEN_MAX;
for (i = j; i < openmax; i += (errno != EINTR)) {
errno = 0;
if (fcntl(i, F_GETFL, 0) < 0 &&
(errno == EBADF || errno == EINTR))
continue;
j = i;
}
openmax = j;
}
return (max_zsh_fd > openmax) ? max_zsh_fd : openmax;
}
/**/
#endif
/*
* Rationalise the current directory, returning the string.
*
* If "d" is not NULL, it is used to store information about the
* directory. The returned name is also present in d->dirname and is in
* permanently allocated memory. The handling of this case depends on
* whether the fchdir() system call is available; if it is, it is assumed
* the caller is able to restore the current directory. On successfully
* identifying the directory the function returns immediately rather
* than ascending the hierarchy.
*
* If "d" is NULL, no assumption about the caller's behaviour is
* made. The returned string is in heap memory. This case is
* always handled by changing directory up the hierarchy.
*
* On Cygwin or other systems where USE_GETCWD is defined (at the
* time of writing only QNX), we skip all the above and use the
* getcwd() system call.
*/
/**/
mod_export char *
zgetdir(struct dirsav *d)
{
char nbuf[PATH_MAX+3];
char *buf;
int bufsiz, pos;
struct stat sbuf;
ino_t pino;
dev_t pdev;
#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
struct dirent *de;
DIR *dir;
dev_t dev;
ino_t ino;
int len;
#endif
buf = zhalloc(bufsiz = PATH_MAX+1);
pos = bufsiz - 1;
buf[pos] = '\0';
strcpy(nbuf, "../");
if (stat(".", &sbuf) < 0) {
return NULL;
}
/* Record the initial inode and device */
pino = sbuf.st_ino;
pdev = sbuf.st_dev;
if (d)
d->ino = pino, d->dev = pdev;
#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
#ifdef HAVE_FCHDIR
else
#endif
holdintr();
for (;;) {
/* Examine the parent of the current directory. */
if (stat("..", &sbuf) < 0)
break;
/* Inode and device of curtent directory */
ino = pino;
dev = pdev;
/* Inode and device of current directory's parent */
pino = sbuf.st_ino;
pdev = sbuf.st_dev;
/* If they're the same, we've reached the root directory. */
if (ino == pino && dev == pdev) {
if (!buf[pos])
buf[--pos] = '/';
if (d) {
#ifndef HAVE_FCHDIR
zchdir(buf + pos);
noholdintr();
#endif
return d->dirname = ztrdup(buf + pos);
}
zchdir(buf + pos);
noholdintr();
return buf + pos;
}
/* Search the parent for the current directory. */
if (!(dir = opendir("..")))
break;
while ((de = readdir(dir))) {
char *fn = de->d_name;
/* Ignore `.' and `..'. */
if (fn[0] == '.' &&
(fn[1] == '\0' ||
(fn[1] == '.' && fn[2] == '\0')))
continue;
#ifdef HAVE_STRUCT_DIRENT_D_STAT
if(de->d_stat.st_dev == dev && de->d_stat.st_ino == ino) {
/* Found the directory we're currently in */
strncpy(nbuf + 3, fn, PATH_MAX);
break;
}
#else /* !HAVE_STRUCT_DIRENT_D_STAT */
# ifdef HAVE_STRUCT_DIRENT_D_INO
if (dev != pdev || (ino_t) de->d_ino == ino)
# endif /* HAVE_STRUCT_DIRENT_D_INO */
{
/* Maybe found directory, need to check device & inode */
strncpy(nbuf + 3, fn, PATH_MAX);
lstat(nbuf, &sbuf);
if (sbuf.st_dev == dev && sbuf.st_ino == ino)
break;
}
#endif /* !HAVE_STRUCT_DIRENT_D_STAT */
}
closedir(dir);
if (!de)
break; /* Not found */
/*
* We get the "/" free just by copying from nbuf+2 instead
* of nbuf+3, which is where we copied the path component.
* This means buf[pos] is always a "/".
*/
len = strlen(nbuf + 2);
pos -= len;
while (pos <= 1) {
char *newbuf = zhalloc(2*bufsiz);
memcpy(newbuf + bufsiz, buf, bufsiz);
buf = newbuf;
pos += bufsiz;
bufsiz *= 2;
}
memcpy(buf + pos, nbuf + 2, len);
#ifdef HAVE_FCHDIR
if (d)
return d->dirname = ztrdup(buf + pos + 1);
#endif
if (chdir(".."))
break;
}
/*
* Fix up the directory, if necessary.
* We're changing back down the hierarchy, ignore the
* "/" at buf[pos].
*/
if (d) {
#ifndef HAVE_FCHDIR
if (buf[pos])
zchdir(buf + pos + 1);
noholdintr();
#endif
return NULL;
}
if (buf[pos])
zchdir(buf + pos + 1);
noholdintr();
#else /* __CYGWIN__, USE_GETCWD cases */
if (!getcwd(buf, bufsiz)) {
if (d) {
return NULL;
}
} else {
if (d) {
return d->dirname = ztrdup(buf);
}
return buf;
}
#endif
/*
* Something bad happened.
* This has been seen when inside a special directory,
* such as the Netapp .snapshot directory, that doesn't
* appear as a directory entry in the parent directory.
* We'll just need our best guess.
*
* We only get here from zgetcwd(); let that fall back to pwd.
*/
return NULL;
}
/*
* Try to find the current directory.
* If we couldn't work it out internally, fall back to getcwd().
* If it fails, fall back to pwd; if zgetcwd() is being used
* to set pwd, pwd should be NULL and we just return ".".
*/
/**/
char *
zgetcwd(void)
{
char *ret = zgetdir(NULL);
#ifdef HAVE_GETCWD
if (!ret) {
#ifdef GETCWD_CALLS_MALLOC
char *cwd = getcwd(NULL, 0);
if (cwd) {
ret = dupstring(cwd);
free(cwd);
}
#else
char *cwdbuf = zalloc(PATH_MAX+1);
ret = getcwd(cwdbuf, PATH_MAX);
if (ret)
ret = dupstring(ret);
zfree(cwdbuf, PATH_MAX+1);
#endif /* GETCWD_CALLS_MALLOC */
}
#endif /* HAVE_GETCWD */
if (!ret)
ret = unmeta(pwd);
if (!ret)
ret = dupstring(".");
return ret;
}
/*
* chdir with arbitrary long pathname. Returns 0 on success, -1 on normal *
* failure and -2 when chdir failed and the current directory is lost.
*
* This is to be treated as if at system level, so dir is unmetafied but
* terminated by a NULL.
*/
/**/
mod_export int
zchdir(char *dir)
{
char *s;
int currdir = -2;
for (;;) {
if (!*dir || chdir(dir) == 0) {
#ifdef HAVE_FCHDIR
if (currdir >= 0)
close(currdir);
#endif
return 0;
}
if ((errno != ENAMETOOLONG && errno != ENOMEM) ||
strlen(dir) < PATH_MAX)
break;
for (s = dir + PATH_MAX - 1; s > dir && *s != '/'; s--)
;
if (s == dir)
break;
#ifdef HAVE_FCHDIR
if (currdir == -2)
currdir = open(".", O_RDONLY|O_NOCTTY);
#endif
*s = '\0';
if (chdir(dir) < 0) {
*s = '/';
break;
}
#ifndef HAVE_FCHDIR
currdir = -1;
#endif
*s = '/';
while (*++s == '/')
;
dir = s;
}
#ifdef HAVE_FCHDIR
if (currdir >= 0) {
if (fchdir(currdir) < 0) {
close(currdir);
return -2;
}
close(currdir);
return -1;
}
#endif
return currdir == -2 ? -1 : -2;
}
/*
* How to print out a 64 bit integer. This isn't needed (1) if longs
* are 64 bit, since ordinary %ld will work (2) if we couldn't find a
* 64 bit type anyway.
*/
/**/
#ifdef ZSH_64_BIT_TYPE
/**/
mod_export char *
output64(zlong val)
{
static char llbuf[DIGBUFSIZE];
convbase(llbuf, val, 0);
return llbuf;
}
/**/
#endif /* ZSH_64_BIT_TYPE */
/**/
#ifndef HAVE_STRTOUL
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Convert a string to an unsigned long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
/**/
unsigned long
strtoul(nptr, endptr, base)
const char *nptr;
char **endptr;
int base;
{
const char *s;
unsigned long acc, cutoff;
int c;
int neg, any, cutlim;
/* endptr may be NULL */
s = nptr;
do {
c = (unsigned char) *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = ULONG_MAX / (unsigned long)base;
cutlim = (int)(ULONG_MAX % (unsigned long)base);
for (acc = 0, any = 0;; c = (unsigned char) *s++) {
if (isdigit(c))
c -= '0';
else if (isalpha(c)) {
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
} else
break;
if (c >= base)
break;
if (any < 0)
continue;
if (acc > cutoff || (acc == cutoff && c > cutlim)) {
any = -1;
acc = ULONG_MAX;
errno = ERANGE;
} else {
any = 1;
acc *= (unsigned long)base;
acc += c;
}
}
if (neg && any > 0)
acc = -acc;
if (endptr != NULL)
*endptr = any ? s - 1 : nptr;
return (acc);
}
/**/
#endif /* HAVE_STRTOUL */
/**/
#ifdef ENABLE_UNICODE9
#include "./wcwidth9.h"
/**/
int
u9_wcwidth(wchar_t ucs)
{
int w = wcwidth9(ucs);
if (w < -1)
return 1;
return w;
}
/**/
int
u9_iswprint(wint_t ucs)
{
if (ucs == 0)
return 0;
return wcwidth9(ucs) != -1;
}
/**/
#endif /* ENABLE_UNICODE9 */
/**/
#if defined(__APPLE__) && defined(BROKEN_ISPRINT)
/**/
int
isprint_ascii(int c)
{
if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
return (c >= 0x20 && c <= 0x7e);
else
return isprint(c);
}
/**/
#endif /* __APPLE__ && BROKEN_ISPRINT */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
/*
* hashtable.h - header file for hash table handling code
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1997 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
/* Builtin function numbers; used by handler functions that handle more *
* than one builtin. Note that builtins such as compctl, that are not *
* overloaded, don't get a number. */
#define BIN_TYPESET 0
#define BIN_BG 1
#define BIN_FG 2
#define BIN_JOBS 3
#define BIN_WAIT 4
#define BIN_DISOWN 5
#define BIN_BREAK 6
#define BIN_CONTINUE 7
#define BIN_EXIT 8
#define BIN_RETURN 9
#define BIN_CD 10
#define BIN_POPD 11
#define BIN_PUSHD 12
#define BIN_PRINT 13
#define BIN_EVAL 14
#define BIN_SCHED 15
#define BIN_FC 16
#define BIN_R 17
#define BIN_PUSHLINE 18
#define BIN_LOGOUT 19
#define BIN_TEST 20
#define BIN_BRACKET 21
#define BIN_READONLY 22
#define BIN_ECHO 23
#define BIN_DISABLE 24
#define BIN_ENABLE 25
#define BIN_PRINTF 26
#define BIN_COMMAND 27
#define BIN_UNHASH 28
#define BIN_UNALIAS 29
#define BIN_UNFUNCTION 30
#define BIN_UNSET 31
/* These currently depend on being 0 and 1. */
#define BIN_SETOPT 0
#define BIN_UNSETOPT 1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,701 @@
/*
* input.c - read and store lines of input
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1997 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
/*
* This file deals with input buffering, supplying characters to the
* history expansion code a character at a time. Input is stored on a
* stack, which allows insertion of strings into the input, possibly with
* flags marking the end of alias expansion, with minimal copying of
* strings. The same stack is used to record the fact that the input
* is a history or alias expansion and to store the alias while it is in use.
*
* Input is taken either from zle, if appropriate, or read directly from
* the input file, or may be supplied by some other part of the shell (such
* as `eval' or $(...) substitution). In the last case, it should be
* supplied by pushing a new level onto the stack, via inpush(input_string,
* flag, alias); if the current input really needs to be altered, use
* inputsetline(input_string, flag). `Flag' can include or's of INP_FREE
* (if the input string is to be freed when used), INP_CONT (if the input
* is to continue onto what's already in the input queue), INP_ALIAS
* (push supplied alias onto stack) or INP_HIST (ditto, but used to
* mark history expansion). `alias' is ignored unless INP_ALIAS or
* INP_HIST is supplied. INP_ALIAS is always set if INP_HIST is.
*
* Note that the input string is itself used as the input buffer: it is not
* copied, nor is it every written back to, so using a constant string
* should work. Consequently, when passing areas of memory from the heap
* it is necessary that that heap last as long as the operation of reading
* the string. After the string is read, the stack should be popped with
* inpop(), which effectively flushes any unread input as well as restoring
* the previous input state.
*
* The internal flags INP_ALCONT and INP_HISTCONT show that the stack
* element was pushed by an alias or history expansion; they should not
* be needed elsewhere.
*
* The global variable inalmore is set to indicate aliases should
* continue to be expanded because the last alias expansion ended
* in a space. It is only reset after a complete word was read
* without expanding a new alias, in exalias().
*
* PWS 1996/12/10
*/
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#include "zsh.mdh"
#include "input.pro"
/* the shell input fd */
/**/
int SHIN;
/* buffered shell input for non-interactive shells */
/**/
FILE *bshin;
/* != 0 means we are reading input from a string */
/**/
int strin;
/* total # of characters waiting to be read. */
/**/
mod_export int inbufct;
/* the flags controlling the input routines in input.c: see INP_* in zsh.h */
/**/
int inbufflags;
static char *inbuf; /* Current input buffer */
static char *inbufptr; /* Pointer into input buffer */
static char *inbufpush; /* Character at which to re-push alias */
static int inbufleft; /* Characters left in current input
stack element */
/* Input must be stacked since the input queue is used by
* various different parts of the shell.
*/
struct instacks {
char *buf, *bufptr;
Alias alias;
int bufleft, bufct, flags;
};
static struct instacks *instack, *instacktop;
/*
* Input stack size. We need to push the stack for aliases, history
* expansion, and reading from internal strings: only if these operations
* are nested do we need more than one extra level. Thus we shouldn't need
* too much space as a rule. Initially, INSTACK_INITIAL is allocated; if
* more is required, an extra INSTACK_EXPAND is added each time.
*/
#define INSTACK_INITIAL 4
#define INSTACK_EXPAND 4
static int instacksz = INSTACK_INITIAL;
/* Read a line from bshin. Convert tokens and *
* null characters to Meta c^32 character pairs. */
/**/
mod_export char *
shingetline(void)
{
char *line = NULL;
int ll = 0;
int c;
char buf[BUFSIZ];
char *p;
int q = queue_signal_level();
p = buf;
winch_unblock();
dont_queue_signals();
for (;;) {
/* Can't fgets() here because we need to accept '\0' bytes */
do {
errno = 0;
c = fgetc(bshin);
} while (c < 0 && errno == EINTR);
if (c < 0 || c == '\n') {
winch_block();
restore_queue_signals(q);
if (c == '\n')
*p++ = '\n';
if (p > buf) {
*p++ = '\0';
line = zrealloc(line, ll + (p - buf));
memcpy(line + ll, buf, p - buf);
}
return line;
}
if (imeta(c)) {
*p++ = Meta;
*p++ = c ^ 32;
} else
*p++ = c;
if (p >= buf + BUFSIZ - 1) {
winch_block();
queue_signals();
line = zrealloc(line, ll + (p - buf) + 1);
memcpy(line + ll, buf, p - buf);
ll += p - buf;
line[ll] = '\0';
p = buf;
winch_unblock();
dont_queue_signals();
}
}
}
/* Get the next character from the input.
* Will call inputline() to get a new line where necessary.
*/
/**/
int
ingetc(void)
{
int lastc = ' ';
if (lexstop)
return ' ';
for (;;) {
if (inbufleft) {
inbufleft--;
inbufct--;
if (itok(lastc = STOUC(*inbufptr++)))
continue;
if (((inbufflags & INP_LINENO) || !strin) && lastc == '\n')
lineno++;
break;
}
/*
* See if we have reached the end of input
* (due to an error, or to reading from a single string).
* Check the remaining characters left, since if there aren't
* any we don't want to pop the stack---it'll mark any aliases
* as not in use before we've finished processing.
*/
if (!inbufct && (strin || errflag)) {
lexstop = 1;
break;
}
/* If the next element down the input stack is a continuation of
* this, use it.
*/
if (inbufflags & INP_CONT) {
inpoptop();
continue;
}
/* As a last resort, get some more input */
if (inputline())
break;
}
if (!lexstop)
zshlex_raw_add(lastc);
return lastc;
}
/* Read a line from the current command stream and store it as input */
/**/
static int
inputline(void)
{
char *ingetcline, **ingetcpmptl = NULL, **ingetcpmptr = NULL;
int context = ZLCON_LINE_START;
/* If reading code interactively, work out the prompts. */
if (interact && isset(SHINSTDIN)) {
if (!isfirstln) {
ingetcpmptl = &prompt2;
if (rprompt2)
ingetcpmptr = &rprompt2;
context = ZLCON_LINE_CONT;
}
else {
ingetcpmptl = &prompt;
if (rprompt)
ingetcpmptr = &rprompt;
}
}
if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
/*
* If not using zle, read the line straight from the input file.
* Possibly we don't get the whole line at once: in that case,
* we get another chunk with the next call to inputline().
*/
if (interact && isset(SHINSTDIN)) {
/*
* We may still be interactive (e.g. running under emacs),
* so output a prompt if necessary. We don't know enough
* about the input device to be able to handle an rprompt,
* though.
*/
char *pptbuf;
int pptlen;
pptbuf = unmetafy(promptexpand(ingetcpmptl ? *ingetcpmptl : NULL,
0, NULL, NULL, NULL), &pptlen);
write_loop(2, pptbuf, pptlen);
free(pptbuf);
}
ingetcline = shingetline();
} else {
/*
* Since we may have to read multiple lines before getting
* a complete piece of input, we tell zle not to restore the
* original tty settings after reading each chunk. Instead,
* this is done when the history mechanism for the current input
* terminates, which is not until we have the whole input.
* This is supposed to minimise problems on systems that clobber
* typeahead when the terminal settings are altered.
* pws 1998/03/12
*/
int flags = ZLRF_HISTORY|ZLRF_NOSETTY;
if (isset(IGNOREEOF))
flags |= ZLRF_IGNOREEOF;
ingetcline = zleentry(ZLE_CMD_READ, ingetcpmptl, ingetcpmptr,
flags, context);
histdone |= HISTFLAG_SETTY;
}
if (!ingetcline) {
return lexstop = 1;
}
if (errflag) {
free(ingetcline);
errflag |= ERRFLAG_ERROR;
return lexstop = 1;
}
if (isset(VERBOSE)) {
/* Output the whole line read so far. */
zputs(ingetcline, stderr);
fflush(stderr);
}
if (keyboardhackchar && *ingetcline &&
ingetcline[strlen(ingetcline) - 1] == '\n' &&
interact && isset(SHINSTDIN) &&
SHTTY != -1 && ingetcline[1])
{
char *stripptr = ingetcline + strlen(ingetcline) - 2;
if (*stripptr == keyboardhackchar) {
/* Junk an unwanted character at the end of the line.
(key too close to return key) */
int ct = 1; /* force odd */
char *ptr;
if (keyboardhackchar == '\'' || keyboardhackchar == '"' ||
keyboardhackchar == '`') {
/*
* for the chars above, also require an odd count before
* junking
*/
for (ct = 0, ptr = ingetcline; *ptr; ptr++)
if (*ptr == keyboardhackchar)
ct++;
}
if (ct & 1) {
stripptr[0] = '\n';
stripptr[1] = '\0';
}
}
}
isfirstch = 1;
if ((inbufflags & INP_APPEND) && inbuf) {
/*
* We need new input but need to be able to back up
* over the old input, so append this line.
* Pushing the line onto the stack doesn't have the right
* effect.
*
* This is quite a simple and inefficient fix, but currently
* we only need it when backing up over a multi-line $((...
* that turned out to be a command substitution rather than
* a math substitution, which is a very special case.
* So it's not worth rewriting.
*/
char *oinbuf = inbuf;
int newlen = strlen(ingetcline);
int oldlen = (int)(inbufptr - inbuf) + inbufleft;
if (inbufflags & INP_FREE) {
inbuf = realloc(inbuf, oldlen + newlen + 1);
} else {
inbuf = zalloc(oldlen + newlen + 1);
memcpy(inbuf, oinbuf, oldlen);
}
inbufptr += inbuf - oinbuf;
strcpy(inbuf + oldlen, ingetcline);
free(ingetcline);
inbufleft += newlen;
inbufct += newlen;
inbufflags |= INP_FREE;
} else {
/* Put this into the input channel. */
inputsetline(ingetcline, INP_FREE);
}
return 0;
}
/*
* Put a string in the input queue:
* inbuf is only freeable if the flags include INP_FREE.
*/
/**/
static void
inputsetline(char *str, int flags)
{
queue_signals();
if ((inbufflags & INP_FREE) && inbuf) {
free(inbuf);
}
inbuf = inbufptr = str;
inbufleft = strlen(inbuf);
/*
* inbufct must reflect the total number of characters left,
* as it used by other parts of the shell, so we need to take account
* of whether the input stack continues, and whether there
* is an extra space to add on at the end.
*/
if (flags & INP_CONT)
inbufct += inbufleft;
else
inbufct = inbufleft;
inbufflags = flags;
unqueue_signals();
}
/*
* Backup one character of the input.
* The last character can always be backed up, provided we didn't just
* expand an alias or a history reference.
* In fact, the character is ignored and the previous character is used.
* (If that's wrong, the bug is in the calling code. Use the #ifdef DEBUG
* code to check.)
*/
/**/
void
inungetc(int c)
{
if (!lexstop) {
if (inbufptr != inbuf) {
#ifdef DEBUG
/* Just for debugging: enable only if foul play suspected. */
if (inbufptr[-1] != (char) c)
fprintf(stderr, "Warning: backing up wrong character.\n");
#endif
/* Just decrement the pointer: if it's not the same
* character being pushed back, we're in trouble anyway.
*/
inbufptr--;
inbufct++;
inbufleft++;
if (((inbufflags & INP_LINENO) || !strin) && c == '\n')
lineno--;
}
else if (!(inbufflags & INP_CONT)) {
#ifdef DEBUG
/* Just for debugging */
fprintf(stderr, "Attempt to inungetc() at start of input.\n");
#endif
zerr("Garbled input at %c (binary file as commands?)", c);
return;
}
else {
/*
* The character is being backed up from a previous input stack
* layer. However, there was an expansion in the middle, so we
* can't back up where we want to. Instead, we just push it
* onto the input stack as an extra character.
*/
char *cback = (char *)zshcalloc(2);
cback[0] = (char) c;
inpush(cback, INP_FREE|INP_CONT, NULL);
}
/* If we are back at the start of a segment,
* we may need to restore an alias popped from the stack.
* Note this may be a dummy (history expansion) entry.
*/
if (inbufptr == inbufpush &&
(inbufflags & (INP_ALCONT|INP_HISTCONT))) {
/*
* Go back up the stack over all entries which were alias
* expansions and were pushed with nothing remaining to read.
*/
do {
if (instacktop->alias)
instacktop->alias->inuse = 1;
instacktop++;
} while ((instacktop->flags & (INP_ALCONT|INP_HISTCONT))
&& !instacktop->bufleft);
if (inbufflags & INP_HISTCONT)
inbufflags = INP_CONT|INP_ALIAS|INP_HIST;
else
inbufflags = INP_CONT|INP_ALIAS;
inbufleft = 0;
inbuf = inbufptr = "";
}
zshlex_raw_back();
}
}
/* stuff a whole file into the input queue and print it */
/**/
int
stuff(char *fn)
{
FILE *in;
char *buf;
off_t len;
if (!(in = fopen(unmeta(fn), "r"))) {
zerr("can't open %s", fn);
return 1;
}
fseek(in, 0, 2);
len = ftell(in);
fseek(in, 0, 0);
buf = (char *)zalloc(len + 1);
if (!(fread(buf, len, 1, in))) {
zerr("read error on %s", fn);
fclose(in);
zfree(buf, len + 1);
return 1;
}
fclose(in);
buf[len] = '\0';
fwrite(buf, len, 1, stderr);
fflush(stderr);
inputsetline(metafy(buf, len, META_REALLOC), INP_FREE);
return 0;
}
/* flush input queue */
/**/
void
inerrflush(void)
{
while (!lexstop && inbufct)
ingetc();
}
/* Set some new input onto a new element of the input stack */
/**/
mod_export void
inpush(char *str, int flags, Alias inalias)
{
if (!instack) {
/* Initial stack allocation */
instack = (struct instacks *)zalloc(instacksz*sizeof(struct instacks));
instacktop = instack;
}
instacktop->buf = inbuf;
instacktop->bufptr = inbufptr;
instacktop->bufleft = inbufleft;
instacktop->bufct = inbufct;
inbufflags &= ~(INP_ALCONT|INP_HISTCONT);
if (flags & (INP_ALIAS|INP_HIST)) {
/*
* Text is expansion for history or alias, so continue
* back to old level when done. Also mark stack top
* as alias continuation so as to back up if necessary,
* and mark alias as in use.
*/
flags |= INP_CONT|INP_ALIAS;
if (flags & INP_HIST)
instacktop->flags = inbufflags | INP_HISTCONT;
else
instacktop->flags = inbufflags | INP_ALCONT;
if ((instacktop->alias = inalias))
inalias->inuse = 1;
} else {
/* If we are continuing an alias expansion, record the alias
* expansion in new set of flags (do we need this?)
*/
if (((instacktop->flags = inbufflags) & INP_ALIAS) &&
(flags & INP_CONT))
flags |= INP_ALIAS;
}
instacktop++;
if (instacktop == instack + instacksz) {
/* Expand the stack */
instack = (struct instacks *)
realloc(instack,
(instacksz + INSTACK_EXPAND)*sizeof(struct instacks));
instacktop = instack + instacksz;
instacksz += INSTACK_EXPAND;
}
/*
* We maintain the entry above the highest one with real
* text as a flag to inungetc() that it can stop re-pushing the stack.
*/
instacktop->flags = 0;
inbufpush = inbuf = NULL;
inputsetline(str, flags);
}
/* Remove the top element of the stack */
/**/
static void
inpoptop(void)
{
if (!lexstop) {
inbufflags &= ~(INP_ALCONT|INP_HISTCONT);
while (inbufptr > inbuf) {
inbufptr--;
inbufct++;
inbufleft++;
/*
* As elsewhere in input and history mechanisms:
* unwinding aliases and unwinding history have different
* implications as aliases are after the lexer while
* history is before, but they're both pushed onto
* the input stack.
*/
if ((inbufflags & (INP_ALIAS|INP_HIST|INP_RAW_KEEP)) == INP_ALIAS)
zshlex_raw_back();
}
}
if (inbuf && (inbufflags & INP_FREE))
free(inbuf);
instacktop--;
inbuf = instacktop->buf;
inbufptr = inbufpush = instacktop->bufptr;
inbufleft = instacktop->bufleft;
inbufct = instacktop->bufct;
inbufflags = instacktop->flags;
if (!(inbufflags & (INP_ALCONT|INP_HISTCONT)))
return;
if (instacktop->alias) {
char *t = instacktop->alias->text;
/* a real alias: mark it as unused. */
instacktop->alias->inuse = 0;
if (*t && t[strlen(t) - 1] == ' ') {
inalmore = 1;
histbackword();
}
}
}
/* Remove the top element of the stack and all its continuations. */
/**/
mod_export void
inpop(void)
{
int remcont;
do {
remcont = inbufflags & INP_CONT;
inpoptop();
} while (remcont);
}
/*
* Expunge any aliases from the input stack; they shouldn't appear
* in the history and need to be flushed explicitly when we encounter
* an error.
*/
/**/
void
inpopalias(void)
{
while (inbufflags & INP_ALIAS)
inpoptop();
}
/*
* Get pointer to remaining string to read.
*/
/**/
char *
ingetptr(void)
{
return inbufptr;
}
/*
* Check if the current input line, including continuations, is
* expanding an alias. This does not detect alias expansions that
* have been fully processed and popped from the input stack.
* If there is an alias, the most recently expanded is returned,
* else NULL.
*/
/**/
char *input_hasalias(void)
{
int flags = inbufflags;
struct instacks *instackptr = instacktop;
for (;;)
{
if (!(flags & INP_CONT))
break;
instackptr--;
if (instackptr->alias)
return instackptr->alias->node.nam;
flags = instackptr->flags;
}
return NULL;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,795 @@
/*
* loop.c - loop execution
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1997 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#include "zsh.mdh"
#include "loop.pro"
/* # of nested loops we are in */
/**/
int loops;
/* # of continue levels */
/**/
mod_export int contflag;
/* # of break levels */
/**/
mod_export int breaks;
/**/
int
execfor(Estate state, int do_exec)
{
Wordcode end, loop;
wordcode code = state->pc[-1];
int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
int last = 0;
char *name, *str, *cond = NULL, *advance = NULL;
zlong val = 0;
LinkList vars = NULL, args = NULL;
int old_simple_pline = simple_pline;
/* See comments in execwhile() */
simple_pline = 1;
end = state->pc + WC_FOR_SKIP(code);
if (iscond) {
str = dupstring(ecgetstr(state, EC_NODUP, NULL));
singsub(&str);
if (isset(XTRACE)) {
char *str2 = dupstring(str);
untokenize(str2);
printprompt4();
fprintf(xtrerr, "%s\n", str2);
fflush(xtrerr);
}
if (!errflag) {
matheval(str);
}
if (errflag) {
state->pc = end;
simple_pline = old_simple_pline;
return 1;
}
cond = ecgetstr(state, EC_NODUP, &ctok);
advance = ecgetstr(state, EC_NODUP, &atok);
} else {
vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL);
if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
int htok = 0;
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
state->pc = end;
simple_pline = old_simple_pline;
return 0;
}
if (htok) {
execsubst(args);
if (errflag) {
state->pc = end;
simple_pline = old_simple_pline;
return 1;
}
}
} else {
char **x;
args = newlinklist();
for (x = pparams; *x; x++)
addlinknode(args, dupstring(*x));
}
}
if (!args || empty(args))
lastval = 0;
loops++;
pushheap();
cmdpush(CS_FOR);
loop = state->pc;
while (!last) {
if (iscond) {
if (ctok) {
str = dupstring(cond);
singsub(&str);
} else
str = cond;
if (!errflag) {
while (iblank(*str))
str++;
if (*str) {
if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "%s\n", str);
fflush(xtrerr);
}
val = mathevali(str);
} else
val = 1;
}
if (errflag) {
if (breaks)
breaks--;
lastval = 1;
break;
}
if (!val)
break;
} else {
LinkNode node;
int count = 0;
for (node = firstnode(vars); node; incnode(node))
{
name = (char *)getdata(node);
if (!args || !(str = (char *) ugetnode(args)))
{
if (count) {
str = "";
last = 1;
} else
break;
}
if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "%s=%s\n", name, str);
fflush(xtrerr);
}
setsparam(name, ztrdup(str));
count++;
}
if (!count)
break;
}
state->pc = loop;
execlist(state, 1, do_exec && args && empty(args));
if (breaks) {
breaks--;
if (breaks || !contflag)
break;
contflag = 0;
}
if (retflag)
break;
if (iscond && !errflag) {
if (atok) {
str = dupstring(advance);
singsub(&str);
} else
str = advance;
if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "%s\n", str);
fflush(xtrerr);
}
if (!errflag)
matheval(str);
}
if (errflag) {
if (breaks)
breaks--;
lastval = 1;
break;
}
freeheap();
}
popheap();
cmdpop();
loops--;
simple_pline = old_simple_pline;
state->pc = end;
this_noerrexit = 1;
return lastval;
}
/**/
int
execselect(Estate state, UNUSED(int do_exec))
{
Wordcode end, loop;
wordcode code = state->pc[-1];
char *str, *s, *name;
LinkNode n;
int i, usezle;
FILE *inp;
size_t more;
LinkList args;
int old_simple_pline = simple_pline;
/* See comments in execwhile() */
simple_pline = 1;
end = state->pc + WC_FOR_SKIP(code);
name = ecgetstr(state, EC_NODUP, NULL);
if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
char **x;
args = newlinklist();
for (x = pparams; *x; x++)
addlinknode(args, dupstring(*x));
} else {
int htok = 0;
if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
state->pc = end;
simple_pline = old_simple_pline;
return 0;
}
if (htok) {
execsubst(args);
if (errflag) {
state->pc = end;
simple_pline = old_simple_pline;
return 1;
}
}
}
if (!args || empty(args)) {
state->pc = end;
simple_pline = old_simple_pline;
return 0;
}
loops++;
pushheap();
cmdpush(CS_SELECT);
usezle = interact && SHTTY != -1 && isset(USEZLE);
inp = fdopen(dup(usezle ? SHTTY : 0), "r");
more = selectlist(args, 0);
loop = state->pc;
for (;;) {
for (;;) {
if (empty(bufstack)) {
if (usezle) {
int oef = errflag;
isfirstln = 1;
str = zleentry(ZLE_CMD_READ, &prompt3, NULL,
0, ZLCON_SELECT);
if (errflag)
str = NULL;
/* Keep any user interrupt error status */
errflag = oef | (errflag & ERRFLAG_INT);
} else {
str = promptexpand(prompt3, 0, NULL, NULL, NULL);
zputs(str, stderr);
free(str);
fflush(stderr);
str = fgets(zhalloc(256), 256, inp);
}
} else
str = (char *)getlinknode(bufstack);
if (!str && !errflag)
setsparam("REPLY", ztrdup("")); /* EOF (user pressed Ctrl+D) */
if (!str || errflag) {
if (breaks)
breaks--;
fprintf(stderr, "\n");
fflush(stderr);
goto done;
}
if ((s = strchr(str, '\n')))
*s = '\0';
if (*str)
break;
more = selectlist(args, more);
}
setsparam("REPLY", ztrdup(str));
i = atoi(str);
if (!i)
str = "";
else {
for (i--, n = firstnode(args); n && i; incnode(n), i--);
if (n)
str = (char *) getdata(n);
else
str = "";
}
setsparam(name, ztrdup(str));
state->pc = loop;
execlist(state, 1, 0);
freeheap();
if (breaks) {
breaks--;
if (breaks || !contflag)
break;
contflag = 0;
}
if (retflag || errflag)
break;
}
done:
cmdpop();
popheap();
fclose(inp);
loops--;
simple_pline = old_simple_pline;
state->pc = end;
this_noerrexit = 1;
return lastval;
}
/* And this is used to print select lists. */
/**/
size_t
selectlist(LinkList l, size_t start)
{
size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
char **arr, **ap;
zleentry(ZLE_CMD_TRASH);
arr = hlinklist2array(l, 0);
for (ap = arr; *ap; ap++)
if (strlen(*ap) > longest)
longest = strlen(*ap);
t0 = ct = ap - arr;
longest++;
while (t0)
t0 /= 10, longest++;
/* to compensate for added ')' */
fct = (zterm_columns - 1) / (longest + 3);
if (fct == 0)
fct = 1;
else
fw = (zterm_columns - 1) / fct;
colsz = (ct + fct - 1) / fct;
for (t1 = start; t1 != colsz && t1 - start < zterm_lines - 2; t1++) {
ap = arr + t1;
do {
size_t t2 = strlen(*ap) + 2;
int t3;
fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
while (t3)
t2++, t3 /= 10;
for (; t2 < fw; t2++)
fputc(' ', stderr);
for (t0 = colsz; t0 && *ap; t0--, ap++);
}
while (*ap);
fputc('\n', stderr);
}
/* Below is a simple attempt at doing it the Korn Way..
ap = arr;
t0 = 0;
do {
t0++;
fprintf(stderr,"%d) %s\n",t0,*ap);
ap++;
}
while (*ap);*/
fflush(stderr);
return t1 < colsz ? t1 : 0;
}
/**/
int
execwhile(Estate state, UNUSED(int do_exec))
{
Wordcode end, loop;
wordcode code = state->pc[-1];
int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL);
int old_simple_pline = simple_pline;
end = state->pc + WC_WHILE_SKIP(code);
olderrexit = noerrexit;
oldval = 0;
pushheap();
cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
loops++;
loop = state->pc;
if (loop[0] == WC_END && loop[1] == WC_END) {
/* This is an empty loop. Make sure the signal handler sets the
* flags and then just wait for someone hitting ^C. */
simple_pline = 1;
while (!breaks)
;
breaks--;
simple_pline = old_simple_pline;
} else
for (;;) {
state->pc = loop;
noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN;
/* In case the test condition is a functional no-op,
* make sure signal handlers recognize ^C to end the loop. */
simple_pline = 1;
execlist(state, 1, 0);
simple_pline = old_simple_pline;
noerrexit = olderrexit;
if (!((lastval == 0) ^ isuntil)) {
if (breaks)
breaks--;
if (!retflag)
lastval = oldval;
break;
}
if (retflag)
break;
/* In case the loop body is also a functional no-op,
* make sure signal handlers recognize ^C as above. */
simple_pline = 1;
execlist(state, 1, 0);
simple_pline = old_simple_pline;
if (breaks) {
breaks--;
if (breaks || !contflag)
break;
contflag = 0;
}
if (errflag) {
lastval = 1;
break;
}
if (retflag)
break;
freeheap();
oldval = lastval;
}
cmdpop();
popheap();
loops--;
state->pc = end;
this_noerrexit = 1;
return lastval;
}
/**/
int
execrepeat(Estate state, UNUSED(int do_exec))
{
Wordcode end, loop;
wordcode code = state->pc[-1];
int count, htok = 0;
char *tmp;
int old_simple_pline = simple_pline;
/* See comments in execwhile() */
simple_pline = 1;
end = state->pc + WC_REPEAT_SKIP(code);
lastval = 0;
tmp = ecgetstr(state, EC_DUPTOK, &htok);
if (htok)
singsub(&tmp);
count = mathevali(tmp);
if (errflag)
return 1;
pushheap();
cmdpush(CS_REPEAT);
loops++;
loop = state->pc;
while (count-- > 0) {
state->pc = loop;
execlist(state, 1, 0);
freeheap();
if (breaks) {
breaks--;
if (breaks || !contflag)
break;
contflag = 0;
}
if (errflag) {
lastval = 1;
break;
}
if (retflag)
break;
}
cmdpop();
popheap();
loops--;
simple_pline = old_simple_pline;
state->pc = end;
this_noerrexit = 1;
return lastval;
}
/**/
int
execif(Estate state, int do_exec)
{
Wordcode end, next;
wordcode code = state->pc[-1];
int olderrexit, s = 0, run = 0;
olderrexit = noerrexit;
end = state->pc + WC_IF_SKIP(code);
noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN;
while (state->pc < end) {
code = *state->pc++;
if (wc_code(code) != WC_IF ||
(run = (WC_IF_TYPE(code) == WC_IF_ELSE))) {
if (run)
run = 2;
break;
}
next = state->pc + WC_IF_SKIP(code);
cmdpush(s ? CS_ELIF : CS_IF);
execlist(state, 1, 0);
cmdpop();
if (!lastval) {
run = 1;
break;
}
if (retflag)
break;
s = 1;
state->pc = next;
}
if (run) {
/* we need to ignore lastval until we reach execcmd() */
if (olderrexit)
noerrexit = olderrexit;
else if (lastval)
noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_UNTIL_EXEC;
else
noerrexit &= ~ (NOERREXIT_EXIT | NOERREXIT_RETURN);
cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN));
execlist(state, 1, do_exec);
cmdpop();
} else {
noerrexit = olderrexit;
if (!retflag)
lastval = 0;
}
state->pc = end;
this_noerrexit = 1;
return lastval;
}
/**/
int
execcase(Estate state, int do_exec)
{
Wordcode end, next;
wordcode code = state->pc[-1];
char *word, *pat;
int npat, save, nalts, ialt, patok, anypatok;
Patprog *spprog, pprog;
end = state->pc + WC_CASE_SKIP(code);
word = ecgetstr(state, EC_DUP, NULL);
singsub(&word);
untokenize(word);
anypatok = 0;
cmdpush(CS_CASE);
while (state->pc < end) {
code = *state->pc++;
if (wc_code(code) != WC_CASE)
break;
save = 0;
next = state->pc + WC_CASE_SKIP(code);
nalts = *state->pc++;
ialt = patok = 0;
if (isset(XTRACE)) {
printprompt4();
fprintf(xtrerr, "case %s (", word);
}
while (!patok && nalts) {
npat = state->pc[1];
spprog = state->prog->pats + npat;
pprog = NULL;
pat = NULL;
queue_signals();
if (isset(XTRACE)) {
int htok = 0;
pat = dupstring(ecrawstr(state->prog, state->pc, &htok));
if (htok)
singsub(&pat);
if (ialt++)
fprintf(stderr, " | ");
quote_tokenized_output(pat, xtrerr);
}
if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
pprog = *spprog;
if (!pprog) {
if (!pat) {
char *opat;
int htok = 0;
pat = dupstring(opat = ecrawstr(state->prog,
state->pc, &htok));
if (htok)
singsub(&pat);
save = (!(state->prog->flags & EF_HEAP) &&
!strcmp(pat, opat) && *spprog != dummy_patprog2);
}
if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
NULL)))
zerr("bad pattern: %s", pat);
else if (save)
*spprog = pprog;
}
if (pprog && pattry(pprog, word))
patok = anypatok = 1;
state->pc += 2;
nalts--;
unqueue_signals();
}
state->pc += 2 * nalts;
if (isset(XTRACE)) {
fprintf(xtrerr, ")\n");
fflush(xtrerr);
}
if (patok) {
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
while (!retflag && wc_code(code) == WC_CASE &&
WC_CASE_TYPE(code) == WC_CASE_AND && state->pc < end) {
state->pc = next;
code = *state->pc++;
next = state->pc + WC_CASE_SKIP(code);
nalts = *state->pc++;
state->pc += 2 * nalts;
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
do_exec));
}
if (WC_CASE_TYPE(code) != WC_CASE_TESTAND)
break;
}
state->pc = next;
}
cmdpop();
state->pc = end;
if (!anypatok)
lastval = 0;
this_noerrexit = 1;
return lastval;
}
/*
* Errflag from `try' block, may be reset in `always' block.
* Accessible from an integer parameter, so needs to be a zlong.
*/
/**/
zlong
try_errflag = -1;
/**
* Corresponding interrupt error status form `try' block.
*/
/**/
zlong
try_interrupt = -1;
/**/
zlong
try_tryflag = 0;
/**/
int
exectry(Estate state, int do_exec)
{
Wordcode end, always;
int endval;
int save_retflag, save_breaks, save_contflag;
zlong save_try_errflag, save_try_tryflag, save_try_interrupt;
end = state->pc + WC_TRY_SKIP(state->pc[-1]);
always = state->pc + 1 + WC_TRY_SKIP(*state->pc);
state->pc++;
pushheap();
cmdpush(CS_CURSH);
/* The :try clause */
save_try_tryflag = try_tryflag;
try_tryflag = 1;
execlist(state, 1, do_exec);
try_tryflag = save_try_tryflag;
/* Don't record errflag here, may be reset. However, */
/* endval should show failure when there is an error. */
endval = lastval ? lastval : errflag;
freeheap();
cmdpop();
cmdpush(CS_ALWAYS);
/* The always clause. */
save_try_errflag = try_errflag;
save_try_interrupt = try_interrupt;
try_errflag = (zlong)(errflag & ERRFLAG_ERROR);
try_interrupt = (zlong)((errflag & ERRFLAG_INT) ? 1 : 0);
/* We need to reset all errors to allow the block to execute */
errflag = 0;
save_retflag = retflag;
retflag = 0;
save_breaks = breaks;
breaks = 0;
save_contflag = contflag;
contflag = 0;
state->pc = always;
execlist(state, 1, do_exec);
if (try_errflag)
errflag |= ERRFLAG_ERROR;
else
errflag &= ~ERRFLAG_ERROR;
if (try_interrupt)
errflag |= ERRFLAG_INT;
else
errflag &= ~ERRFLAG_INT;
try_errflag = save_try_errflag;
try_interrupt = save_try_interrupt;
if (!retflag)
retflag = save_retflag;
if (!breaks)
breaks = save_breaks;
if (!contflag)
contflag = save_contflag;
cmdpop();
popheap();
state->pc = end;
return endval;
}

View File

@ -0,0 +1,166 @@
#
# makepro.awk - generate prototype lists
#
BEGIN {
aborting = 0
# arg 1 is the name of the file to process
# arg 2 is the name of the subdirectory it is in
if(ARGC != 3) {
aborting = 1
exit 1
}
name = ARGV[1]
gsub(/^.*\//, "", name)
gsub(/\.c$/, "", name)
name = ARGV[2] "_" name
gsub(/\//, "_", name)
ARGC--
printf "E#ifndef have_%s_globals\n", name
printf "E#define have_%s_globals\n", name
printf "E\n"
}
# all relevant declarations are preceded by "/**/" on a line by itself
/^\/\*\*\/$/ {
# The declaration is on following lines. The interesting part might
# be terminated by a `{' (`int foo(void) { }' or `int bar[] = {')
# or `;' (`int x;').
line = ""
isfunc = 0
while(1) {
if(getline <= 0) {
aborting = 1
exit 1
}
if (line == "" && $0 ~ /^[ \t]*#/) {
# Directly after the /**/ was a preprocessor line.
# Spit it out and re-start the outer loop.
printf "E%s\n", $0
printf "L%s\n", $0
next
}
gsub(/\t/, " ")
line = line " " $0
gsub(/\/\*([^*]|\*+[^*\/])*\*+\//, " ", line)
if(line ~ /\/\*/)
continue
# If it is a function definition, note so.
if(line ~ /\) *(VA_DCL )*[{].*$/) #}
isfunc = 1
if(sub(/ *[{;].*$/, "", line)) #}
break
}
if (!match(line, /VA_ALIST/)) {
# Put spaces around each identifier.
while(match(line, /[^_0-9A-Za-z ][_0-9A-Za-z]/) ||
match(line, /[_0-9A-Za-z][^_0-9A-Za-z ]/))
line = substr(line, 1, RSTART) " " substr(line, RSTART+1)
}
# Separate declarations into a type and a list of declarators.
# In each declarator, "@{" and "@}" are used in place of parens to
# mark function parameter lists, and "@!" is used in place of commas
# in parameter lists. "@<" and "@>" are used in place of
# non-parameter list parens.
gsub(/ _ +/, " _ ", line)
while(1) {
if(isfunc && match(line, /\([^()]*\)$/))
line = substr(line, 1, RSTART-1) " _ (" substr(line, RSTART) ")"
else if(match(line, / _ \(\([^,()]*,/))
line = substr(line, 1, RSTART+RLENGTH-2) "@!" substr(line, RSTART+RLENGTH)
else if(match(line, / _ \(\([^,()]*\)\)/))
line = substr(line, 1, RSTART-1) "@{" substr(line, RSTART+5, RLENGTH-7) "@}" substr(line, RSTART+RLENGTH)
else if(match(line, /\([^,()]*\)/))
line = substr(line, 1, RSTART-1) "@<" substr(line, RSTART+1, RLENGTH-2) "@>" substr(line, RSTART+RLENGTH)
else
break
}
sub(/^ */, "", line)
match(line, /^((const|enum|mod_export|static|struct|union) +)*([_0-9A-Za-z]+ +|((char|double|float|int|long|short|unsigned|void) +)+)((const|static) +)*/)
dtype = substr(line, 1, RLENGTH)
sub(/ *$/, "", dtype)
if(" " dtype " " ~ / static /)
locality = "L"
else
locality = "E"
exported = " " dtype " " ~ / mod_export /
line = substr(line, RLENGTH+1) ","
# Handle each declarator.
if (match(line, /VA_ALIST/)) {
# Already has VARARGS handling.
# Put parens etc. back
gsub(/@[{]/, "((", line)
gsub(/@}/, "))", line)
gsub(/@</, "(", line)
gsub(/@>/, ")", line)
gsub(/@!/, ",", line)
sub(/,$/, ";", line)
gsub(/mod_export/, "mod_import_function", dtype)
gsub(/VA_ALIST/, "VA_ALIST_PROTO", line)
sub(/ VA_DCL/, "", line)
if(locality ~ /E/)
dtype = "extern " dtype
if (match(line, /[_0-9A-Za-z]+\(VA_ALIST/))
dnam = substr(line, RSTART, RLENGTH-9)
# If this is exported, add it to the exported symbol list.
if (exported)
printf "X%s\n", dnam
printf "%s%s %s\n", locality, dtype, line
} else {
while(match(line, /^[^,]*,/)) {
# Separate out the name from the declarator. Use "@+" and "@-"
# to bracket the name within the declarator. Strip off any
# initialiser.
dcltor = substr(line, 1, RLENGTH-1)
line = substr(line, RLENGTH+1)
sub(/\=.*$/, "", dcltor)
match(dcltor, /^([^_0-9A-Za-z]| const )*/)
dcltor = substr(dcltor, 1, RLENGTH) "@+" substr(dcltor, RLENGTH+1)
match(dcltor, /^.*@\+[_0-9A-Za-z]+/)
dcltor = substr(dcltor, 1, RLENGTH) "@-" substr(dcltor, RLENGTH+1)
dnam = dcltor
sub(/^.*@\+/, "", dnam)
sub(/@-.*$/, "", dnam)
# Put parens etc. back
gsub(/@[{]/, " _((", dcltor)
gsub(/@}/, "))", dcltor)
gsub(/@</, "(", dcltor)
gsub(/@>/, ")", dcltor)
gsub(/@!/, ",", dcltor)
# If this is exported, add it to the exported symbol list.
if(exported)
printf "X%s\n", dnam
# Format the declaration for output
dcl = dtype " " dcltor ";"
if(locality ~ /E/)
dcl = "extern " dcl
if(isfunc)
gsub(/ mod_export /, " mod_import_function ", dcl)
else
gsub(/ mod_export /, " mod_import_variable ", dcl)
gsub(/@[+-]/, "", dcl)
gsub(/ +/, " ", dcl)
while(match(dcl, /[^_0-9A-Za-z] ./) || match(dcl, /. [^_0-9A-Za-z]/))
dcl = substr(dcl, 1, RSTART) substr(dcl, RSTART+2)
printf "%s%s\n", locality, dcl
}
}
}
END {
if(aborting)
exit 1
printf "E\n"
printf "E#endif /* !have_%s_globals */\n", name
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
#! /bin/sh
#
# mkbltnmlst.sh: generate boot code for linked-in modules
#
# Written by Andrew Main
#
srcdir=${srcdir-`echo $0|sed 's%/[^/][^/]*$%%'`}
test "x$srcdir" = "x$0" && srcdir=.
test "x$srcdir" = "x" && srcdir=.
CFMOD=${CFMOD-$srcdir/../config.modules}
bin_mods="`grep ' link=static' $CFMOD | sed -e '/^#/d' \
-e 's/ .*/ /' -e 's/^name=/ /'`"
x_mods="`grep ' load=yes' $CFMOD | sed -e '/^#/d' -e '/ link=no/d' \
-e 's/ .*/ /' -e 's/^name=/ /'`"
trap "rm -f $1; exit 1" 1 2 15
exec > $1
for x_mod in $x_mods; do
modfile="`grep '^name='$x_mod' ' $CFMOD | sed -e 's/^.* modfile=//' \
-e 's/ .*//'`"
if test "x$modfile" = x; then
echo >&2 "WARNING: no name for \`$x_mod' in $CFMOD (ignored)"
continue
fi
case "$bin_mods" in
*" $x_mod "*)
echo "/* linked-in known module \`$x_mod' */"
linked=yes
;;
*)
echo "#ifdef DYNAMIC"
echo "/* non-linked-in known module \`$x_mod' */"
linked=no
esac
unset moddeps autofeatures autofeatures_emu
. $srcdir/../$modfile
if test "x$autofeatures" != x; then
if test "x$autofeatures_emu" != x; then
echo " {"
echo " char *zsh_features[] = { "
for feature in $autofeatures; do
echo " \"$feature\","
done
echo " NULL"
echo " }; "
echo " char *emu_features[] = { "
for feature in $autofeatures_emu; do
echo " \"$feature\","
done
echo " NULL"
echo " }; "
echo " autofeatures(\"zsh\", \"$x_mod\","
echo " EMULATION(EMULATE_ZSH) ? zsh_features : emu_features,"
echo " 0, 1);"
echo " }"
else
echo " if (EMULATION(EMULATE_ZSH)) {"
echo " char *features[] = { "
for feature in $autofeatures; do
echo " \"$feature\","
done
echo " NULL"
echo " }; "
echo " autofeatures(\"zsh\", \"$x_mod\", features, 0, 1);"
echo " }"
fi
fi
for dep in $moddeps; do
echo " add_dep(\"$x_mod\", \"$dep\");"
done
test "x$linked" = xno && echo "#endif"
done
echo
done_mods=" "
for bin_mod in $bin_mods; do
q_bin_mod=`echo $bin_mod | sed 's,Q,Qq,g;s,_,Qu,g;s,/,Qs,g'`
modfile="`grep '^name='$bin_mod' ' $CFMOD | sed -e 's/^.* modfile=//' \
-e 's/ .*//'`"
echo "/* linked-in module \`$bin_mod' */"
unset moddeps
. $srcdir/../$modfile
for dep in $moddeps; do
# This assumes there are no circular dependencies in the builtin
# modules. Better ordering of config.modules would be necessary
# to enforce stricter dependency checking.
case $bin_mods in
*" $dep "*)
echo " /* depends on \`$dep' */" ;;
*) echo >&2 "ERROR: linked-in module \`$bin_mod' depends on \`$dep'"
rm -f $1
exit 1 ;;
esac
done
echo " {"
echo " extern int setup_${q_bin_mod} _((Module));"
echo " extern int boot_${q_bin_mod} _((Module));"
echo " extern int features_${q_bin_mod} _((Module,char***));"
echo " extern int enables_${q_bin_mod} _((Module,int**));"
echo " extern int cleanup_${q_bin_mod} _((Module));"
echo " extern int finish_${q_bin_mod} _((Module));"
echo
echo " register_module(\"$bin_mod\","
echo " setup_${q_bin_mod},"
echo " features_${q_bin_mod},"
echo " enables_${q_bin_mod},"
echo " boot_${q_bin_mod},"
echo " cleanup_${q_bin_mod}, finish_${q_bin_mod});"
echo " }"
done_mods="$done_mods$bin_mod "
done

Some files were not shown because too many files have changed in this diff Show More