mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	zsh-3.1.5-pws-2
This commit is contained in:
		
							parent
							
								
									a61dc2074a
								
							
						
					
					
						commit
						f13624e0f8
					
				
					 27 changed files with 852 additions and 375 deletions
				
			
		|  | @ -139,9 +139,13 @@ install.info: zsh.info | |||
| 	  elif test -f $(sdir)/$$file; then \
 | ||||
| 	    $(INSTALL_DATA) $(sdir)/$$file $(infodir); \
 | ||||
| 	  else :; \
 | ||||
| 	  fi || exit 1; \
 | ||||
| 	   fi || exit 1; \
 | ||||
| 	done | ||||
| 
 | ||||
| install.html: zsh_toc.html | ||||
| 	$(sdir_top)/mkinstalldirs $(htmldir) | ||||
| 	$(INSTALL_DATA) *.html $(htmldir) | ||||
| 
 | ||||
| # uninstall man pages
 | ||||
| uninstall.man: | ||||
| 	for file in $(MAN); do \
 | ||||
|  |  | |||
|  | @ -98,12 +98,13 @@ Change the current directory.  In the first form, change the | |||
| current directory to var(arg), or to the value of tt($HOME) if | ||||
| var(arg) is not specified.  If var(arg) is `tt(-)', change to the | ||||
| value of tt($OLDPWD), the previous directory. | ||||
| If a directory named var(arg) is not found in the current directory | ||||
| and var(arg) does not begin with a slash, | ||||
| search each component of the shell parameter tt(cdpath). | ||||
| If the option tt(CDABLE_VARS) is set, and a parameter named var(arg) | ||||
| exists whose value begins with a slash, treat its value as | ||||
| the directory. | ||||
| Otherwise, if a directory named var(arg) is not found in the current | ||||
| directory and var(arg) does not begin with a slash, search each | ||||
| component of the shell parameter tt(cdpath).  If no directory is found | ||||
| and the option tt(CDABLE_VARS) is set, and a parameter named var(arg) | ||||
| exists whose value begins with a slash, treat its value as the | ||||
| directory.  In that case, the parameter is added to the named | ||||
| directory hash table. | ||||
| 
 | ||||
| The second form of tt(cd) substitutes the string var(new) | ||||
| for the string var(old) in the name of the current directory, | ||||
|  | @ -357,11 +358,20 @@ is stored in tt(OPTARG). | |||
| vindex(OPTIND, use of) | ||||
| vindex(OPTARG, use of) | ||||
| 
 | ||||
| The first option to be examined may be changed by explicitly assigning | ||||
| to tt(OPTIND).  tt(OPTIND) has an initial value of tt(1), and is | ||||
| normally reset to tt(1) upon exit from a shell function.  tt(OPTARG) | ||||
| is not reset and retains its value from the most recent call to | ||||
| tt(getopts).  If either of tt(OPTIND) or tt(OPTARG) is explicitly | ||||
| unset, it remains unset, and the index or option argument is not | ||||
| stored.  The option itself is still stored in var(name) in this case. | ||||
| 
 | ||||
| A leading `tt(:)' in var(optstring) causes tt(getopts) to store the | ||||
| letter of the invalid option in tt(OPTARG), and to set var(name) | ||||
| to `tt(?)' for an unknown option and to `tt(:)' when a required option | ||||
| is missing.  Otherwise, tt(getopts) prints an error | ||||
| message.  The exit status is nonzero when there are no more options. | ||||
| letter of any invalid option in tt(OPTARG), and to set var(name) to | ||||
| `tt(?)' for an unknown option and to `tt(:)' when a required option is | ||||
| missing.  Otherwise, tt(getopts) sets var(name) to `tt(?)' and prints | ||||
| an error message when an option is invalid.  The exit status is | ||||
| nonzero when there are no more options. | ||||
| ) | ||||
| findex(hash) | ||||
| item(tt(hash) [ tt(-dfmrv) ] [ var(name)[tt(=)var(value)] ] ...)( | ||||
|  | @ -521,8 +531,8 @@ Same as tt(exit), except that it only works in a login shell. | |||
| prefix(noglob) | ||||
| findex(popd) | ||||
| item(tt(popd) [ {tt(PLUS())|tt(-)}var(n) ])( | ||||
| Removes a entry from the directory stack, and perform a tt(cd) to | ||||
| the new top directory. With no argument, the current top entry is | ||||
| Remove an entry from the directory stack, and perform a tt(cd) to | ||||
| the new top directory.  With no argument, the current top entry is | ||||
| removed.  An argument of the form `tt(PLUS())var(n)' identifies a stack | ||||
| entry by counting from the left of the list shown by the tt(dirs) command, | ||||
| starting with zero.  An argument of the form tt(-n) counts from the right. | ||||
|  | @ -615,21 +625,9 @@ If var(arg) is not specified, change to the second directory | |||
| on the stack (that is, exchange the top two entries), or | ||||
| change to tt($HOME) if the tt(PUSHD_TO_HOME) | ||||
| option is set or if there is only one entry on the stack. | ||||
| 
 | ||||
| If var(arg) is `tt(-)', change to tt($OLDPWD), the previous directory. | ||||
| If a directory named var(arg) is not found in the current directory | ||||
| and var(arg) does not contain a slash, | ||||
| search each component of the shell parameter tt(cdpath). | ||||
| If the option tt(CDABLE_VARS) is set, and a parameter named var(arg) | ||||
| exists whose value begins with a slash, treat its value as | ||||
| the directory. | ||||
| 
 | ||||
| If the option tt(PUSHD_SILENT) is not set, the directory | ||||
| stack will be printed after a tt(pushd) is performed. | ||||
| 
 | ||||
| The second form of tt(pushd) substitutes the string var(new) | ||||
| for the string var(old) in the name of the current directory, | ||||
| and tries to change to this new directory. | ||||
| Otherwise, var(arg) is interpreted as it would be by tt(cd). | ||||
| The meaning of var(old) and var(new) in the second form is also | ||||
| the same as for tt(cd). | ||||
| 
 | ||||
| The third form of tt(pushd) changes directory by rotating the | ||||
| directory list.  An argument of the form `tt(PLUS())var(n)' identifies a stack | ||||
|  | @ -637,6 +635,9 @@ entry by counting from the left of the list shown by the tt(dirs) | |||
| command, starting with zero.  An argument of the form `tt(-)var(n)' counts | ||||
| from the right.  If the tt(PUSHD_MINUS) option is set, the meanings | ||||
| of `tt(PLUS())' and `tt(-)' in this context are swapped. | ||||
| 
 | ||||
| If the option tt(PUSHD_SILENT) is not set, the directory | ||||
| stack will be printed after a tt(pushd) is performed. | ||||
| ) | ||||
| findex(pushln) | ||||
| item(tt(pushln) [ var(arg) ... ])( | ||||
|  | @ -727,7 +728,8 @@ is interactive. | |||
| 
 | ||||
| The value (exit status) of tt(read) is 1 when an end-of-file is | ||||
| encountered, or when tt(-c) or tt(-l) is present and the command is | ||||
| not called from a tt(compctl) function.  Otherwise the value is 0. | ||||
| not called from a tt(compctl) function, or as described for tt(-q). | ||||
| Otherwise the value is 0. | ||||
| 
 | ||||
| The behavior of some combinations of the tt(-k), tt(-p), tt(-q), tt(-u) | ||||
| and tt(-z) flags is undefined.  Presently tt(-q) cancels all the others, | ||||
|  | @ -835,7 +837,7 @@ var(arg) is a command to be read and executed when the shell | |||
| receives var(sig).  Each var(sig) can be given as a number | ||||
| or as the name of a signal. | ||||
| If var(arg) is `tt(-)', then all traps var(sig) are reset to their | ||||
| default values.  If var(arg) is the null string, then this signal | ||||
| default values.  If var(arg) is the empty string, then this signal | ||||
| is ignored by the shell and by the commands it invokes. | ||||
| 
 | ||||
| If var(sig) is tt(ZERR) then var(arg) will be executed | ||||
|  | @ -958,7 +960,7 @@ or functions (with the tt(-f) flag) with matching names are printed. | |||
| findex(ulimit) | ||||
| cindex(resource limits) | ||||
| cindex(limits, resource) | ||||
| item(tt(ulimit) [ tt(-SHacdflmnpstv) [ tt(limit) ] ... ])( | ||||
| item(tt(ulimit) [ tt(-SHacdflmnpstv) [ var(limit) ] ... ])( | ||||
| Set or display resource limits of the shell and the processes started by | ||||
| the shell.  The value of var(limit) can be a number in the unit specified | ||||
| below or the value `tt(unlimited)'.  If the tt(-H) flag is given use | ||||
|  |  | |||
|  | @ -573,11 +573,11 @@ enditem() | |||
| subsect(Example) | ||||
| The flag tt(f) is useful to split a double-quoted substitution line by | ||||
| line.  For example, `tt("${(f)$LPAR()<)var(file)tt(RPAR()}")' | ||||
| will substitue the contents of var(file) divided so that one line is | ||||
| supplied per argument to var(cmd).  Compare this with the effect of | ||||
| substitutes the contents of var(file) divided so that each line is | ||||
| an element of the resulting array.  Compare this with the effect of | ||||
| `tt($)tt(LPAR()<)var(file)tt(RPAR())' alone, which divides the file | ||||
| up by words, or the same inside double quotes, where the entire | ||||
| contents of the file are passed as a single argument. | ||||
| up by words, or the same inside double quotes, which makes the entire | ||||
| content of the file a single string. | ||||
| texinode(Command Substitution)(Arithmetic Expansion)(Parameter Expansion)(Expansion) | ||||
| sect(Command Substitution) | ||||
| cindex(command substitution) | ||||
|  |  | |||
|  | @ -614,7 +614,7 @@ Thus if `tt(/usr/local/bin)' is in the user's path, and he types | |||
| Commands explicitly beginning with `tt(/)', `tt(./)' or `tt(../)' | ||||
| are not subject to the path search. | ||||
| This also applies to the tt(.) builtin, | ||||
| and searches for modules performed by the tt(zmodload) builtin. | ||||
| and to searches for modules performed by the tt(zmodload) builtin. | ||||
| ) | ||||
| pindex(POSIX_BUILTINS) | ||||
| item(tt(POSIX_BUILTINS))( | ||||
|  |  | |||
|  | @ -175,6 +175,8 @@ sitem(tt(w))(True if the day of the week is equal to var(n) (Sunday = 0).) | |||
| sitem(tt(?))(True if the exit status of the last command was var(n).) | ||||
| sitem(tt(#))(True if the effective uid of the current process is var(n).) | ||||
| sitem(tt(g))(True if the effective gid of the current process is var(n).) | ||||
| sitem(tt(l))(True if at least var(n) characters have already been | ||||
| printed on the current line.) | ||||
| sitem(tt(L))(True if the tt(SHLVL) parameter is at least var(n).) | ||||
| sitem(tt(S))(True if the tt(SECONDS) parameter is at least var(n).) | ||||
| sitem(tt(v))(True if the array tt(psvar) has at least var(n) elements.) | ||||
|  | @ -185,25 +187,40 @@ endsitem() | |||
| xitem(tt(%<)var(string)tt(<)) | ||||
| xitem(tt(%>)var(string)tt(>)) | ||||
| item(tt(%[)var(xstring)tt(]))( | ||||
| Specifies truncation behaviour. | ||||
| Specifies truncation behaviour for the remainder of the prompt string. | ||||
| The third, deprecated, form is equivalent to `tt(%)var(xstringx)', | ||||
| i.e. var(x) may be `tt(<)' or `tt(>)'. | ||||
| The numeric argument, which in the third form may appear immediately | ||||
| after the `tt([)', specifies the maximum permitted length of | ||||
| the various strings that can be displayed in the prompt.  If this | ||||
| integer is zero, or missing, truncation is disabled.  Truncation is | ||||
| initially disabled. | ||||
| the various strings that can be displayed in the prompt. | ||||
| The var(string) will be displayed in | ||||
| place of the truncated portion of any string. | ||||
| place of the truncated portion of any string; note this does not | ||||
| undergo prompt expansion. | ||||
| 
 | ||||
| The forms with `tt(<)' truncate at the left of the string, | ||||
| and the forms with `tt(>)' truncate at the right of the string. | ||||
| For example, if the current directory is `tt(/home/pike)', | ||||
| the prompt `tt(%8<..<%/)' will expand to `tt(..e/pike)'. | ||||
| In this string, the terminating character (`tt(<)', `tt(>)' or `tt(])'), | ||||
| or in fact any character, may be quoted by a preceding `tt(\)'. | ||||
| % escapes are em(not) recognised. | ||||
| or in fact any character, may be quoted by a preceding `tt(\)'; note | ||||
| when using tt(print -P), however, that this must be doubled as the | ||||
| string is also subject to standard tt(print) processing, in addition | ||||
| to any backslashes removed by a double quoted string:  the worst case | ||||
| is therefore `tt(print -P "%<\\\\<<...")'. | ||||
| 
 | ||||
| If the var(string) is longer than the specified truncation length, | ||||
| it will appear in full, completely replacing the truncated string. | ||||
| 
 | ||||
| The part of the prompt string to be truncated runs to the end of the | ||||
| string, or to the end of the next enclosing group of the `tt(%LPAR())' | ||||
| construct, or to the next truncation encountered at the same grouping | ||||
| level (i.e. truncations inside a `tt(%LPAR())' are separate), which | ||||
| ever comes first.  In particular, a truncation with argument zero | ||||
| (e.g. `tt(%<<)') marks the end of the range of the string to be | ||||
| truncated while turning off truncation from there on. For example, the | ||||
| prompt '%10<...<%~%<<%# ' will print a truncated representation of the | ||||
| current directory, followed by a `tt(%)' or `tt(#)', followed by a | ||||
| space.  Without the `tt(%<<)', those two characters would be included | ||||
| in the string to be truncated. | ||||
| ) | ||||
| enditem() | ||||
|  |  | |||
|  | @ -5,8 +5,6 @@ | |||
| # Usage: e.g. | ||||
| # compctl -D -f + -U -Q -S '' -K multicomp | ||||
| # | ||||
| # Note that exactly matched directories are not expanded, e.g. | ||||
| # s/zsh-2.4/s<TAB> will not expand to src/zsh-2.4old/src. | ||||
| # Will expand glob patterns already in the word, but use complete-word, | ||||
| # not TAB (expand-or-complete), or you will get ordinary glob expansion. | ||||
| # Requires the -U option to compctl. | ||||
|  | @ -42,32 +40,32 @@ while [[ -n "$pref" ]]; do | |||
|   [[ "$pref" = /* ]] && sofar=(${sofar}/) && pref="${pref#/}" | ||||
|   head="${pref%%/*}" | ||||
|   pref="${pref#$head}" | ||||
|   if [[ -n "$pref" && -z $sofar[2] && -d "${sofar}$head" ]]; then | ||||
|     # Exactly matched directory: don't try to glob | ||||
|     reply=("${sofar}$head") | ||||
|   [[ -z "$pref" ]] && globdir= | ||||
|   # if path segment contains wildcards, don't add another. | ||||
|   if [[ "$head" = *[\[\(\*\?\$\~]* ]]; then | ||||
|     wild=$head | ||||
|   else | ||||
|     [[ -z "$pref" ]] && globdir= | ||||
|     # if path segment contains wildcards, don't add another. | ||||
|     if [[ "$head" = *[\[\(\*\?\$\~]* || -z "$head" ]]; then | ||||
|       wild=$head | ||||
|     else | ||||
|       # Simulate case-insensitive globbing for ASCII characters | ||||
|       wild="[${(j(][))${(s())head:l}}]*"	# :gs/a/[a]/ etc. | ||||
|       # The following could all be one expansion, but for readability: | ||||
|       wild=$wild:gs/a/aA/:gs/b/bB/:gs/c/cC/:gs/d/dD/:gs/e/eE/:gs/f/fF/ | ||||
|       wild=$wild:gs/g/gG/:gs/h/hH/:gs/i/iI/:gs/j/jJ/:gs/k/kK/:gs/l/lL/ | ||||
|       wild=$wild:gs/m/mM/:gs/n/nN/:gs/o/oO/:gs/p/pP/:gs/q/qQ/:gs/r/rR/ | ||||
|       wild=$wild:gs/s/sS/:gs/t/tT/:gs/u/uU/:gs/v/vV/:gs/w/wW/:gs/x/xX/ | ||||
|       wild=$wild:gs/y/yY/:gs/z/zZ/:gs/-/_/:gs/_/-_/:gs/[]// | ||||
|     # Simulate case-insensitive globbing for ASCII characters | ||||
|     wild="[${(j(][))${(s())head:l}}]*" # :gs/a/[a]/ etc. | ||||
|     # The following could all be one expansion, but for readability: | ||||
|     wild=$wild:gs/a/aA/:gs/b/bB/:gs/c/cC/:gs/d/dD/:gs/e/eE/:gs/f/fF/ | ||||
|     wild=$wild:gs/g/gG/:gs/h/hH/:gs/i/iI/:gs/j/jJ/:gs/k/kK/:gs/l/lL/ | ||||
|     wild=$wild:gs/m/mM/:gs/n/nN/:gs/o/oO/:gs/p/pP/:gs/q/qQ/:gs/r/rR/ | ||||
|     wild=$wild:gs/s/sS/:gs/t/tT/:gs/u/uU/:gs/v/vV/:gs/w/wW/:gs/x/xX/ | ||||
|     wild=$wild:gs/y/yY/:gs/z/zZ/:gs/-/_/:gs/_/-_/:gs/[]// | ||||
| 
 | ||||
|       # Expand on both sides of '.' (except when leading) as for '/' | ||||
|       wild="${${wild:gs/[.]/*.*/}#\*}" | ||||
|     fi | ||||
| 
 | ||||
|     reply=(${sofar}"${wild}${globdir}") | ||||
|     reply=(${~reply}) | ||||
|     # Expand on both sides of '.' (except when leading) as for '/' | ||||
|     wild="${${wild:gs/[.]/*.*/}#\*}" | ||||
|   fi | ||||
| 
 | ||||
|   reply=(${sofar}"${wild}${globdir}") | ||||
|   reply=(${~reply}) | ||||
| 
 | ||||
|   [[ -z $reply[1] ]] && reply=() && break | ||||
|   [[ -n $pref ]] && sofar=($reply) | ||||
| done | ||||
|  | @ -77,4 +75,3 @@ done | |||
| [[ -n "$origtop" ]] && reply=("$origtop"${reply#$newtop}) | ||||
| 
 | ||||
| # } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| # get a random line from a file | ||||
| integer z=$(wc -l <$1) | ||||
| integer z="$(wc -l <$1)" | ||||
| sed -n $[RANDOM%z+1]p $1 | ||||
|  |  | |||
|  | @ -51,6 +51,10 @@ META-FAQ: FORCE | |||
| 
 | ||||
| # ========== DEPENDENCIES FOR INSTALLING ==========
 | ||||
| 
 | ||||
| # install stripped
 | ||||
| install-strip: | ||||
| 	$(MAKE) install STRIPFLAGS="-s" | ||||
| 
 | ||||
| # install/uninstall everything
 | ||||
| install: install.bin install.modules install.man install.info | ||||
| uninstall: uninstall.bin uninstall.modules uninstall.man uninstall.info | ||||
|  | @ -71,6 +75,10 @@ install.man uninstall.man: | |||
| install.info uninstall.info: | ||||
| 	@cd Doc && $(MAKE) $(MAKEDEFS) $@ | ||||
| 
 | ||||
| # install/uninstall just the html pages
 | ||||
| install.html uninstall.html: | ||||
| 	@cd Doc && $(MAKE) $(MAKEDEFS) $@ | ||||
| 
 | ||||
| # ========== DEPENDENCIES FOR CLEANUP ==========
 | ||||
| 
 | ||||
| @@clean.mk@@ | ||||
|  |  | |||
							
								
								
									
										10
									
								
								Misc/c2z
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								Misc/c2z
									
										
									
									
									
								
							|  | @ -3,6 +3,7 @@ | |||
| # c2z - environment conversion tool | ||||
| # Contributed by Bart Schaefer | ||||
| # (Tweaked a bit by Paul Falstad) | ||||
| # (Tweaked again by Bart Schaefer) | ||||
| # | ||||
| # This is a quick script to convert csh aliases to zsh aliases/functions. | ||||
| # It also converts the csh environment and local variables to zsh.  c2z | ||||
|  | @ -81,7 +82,13 @@ grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3 | |||
| sed -e "s/'/'"\\\\"''"/g \ | ||||
|     -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \ | ||||
|     /tmp/cz$$.3 | ||||
| sed -e 's/![:#]*/$/g' \ | ||||
| sed -e 's/>\(&*\)!/>\1|/g' \ | ||||
|     -e 's/!\*:q/"$@"/g' \ | ||||
|     -e 's/\(![:#]*[^'"$T"']*\):q/"\1"/g' \ | ||||
|     -e 's/!\([-0-9][0-9]*\)\(:x\)*/$\2(fc -nl \1)/g' \ | ||||
|     -e 's/\$:x(fc/$=(fc/g' \ | ||||
|     -e 's/![:#]*\([^'"$T"']\)/$==\1/g' \ | ||||
|     -e 's/\$=\(=[^'"$T"']*\):x/$\1/g' \ | ||||
|     -e 's/\$cwd/$PWD/' \ | ||||
|     -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \ | ||||
|     /tmp/cz$$.2 | ||||
|  | @ -92,6 +99,7 @@ exec < /tmp/cz$$.e | |||
| # Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ... | ||||
| sed -e '/^SHLVL/d' \ | ||||
|     -e '/^PWD/d' \ | ||||
|     -e '/^_=/d' \ | ||||
|     -e "s/'/'"\\\\"''"/g \ | ||||
|     -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \ | ||||
|     -e "s/$/'/" | ||||
|  |  | |||
|  | @ -149,7 +149,7 @@ uninstall.bin: uninstall.bin-here | |||
| # install binary, creating install directory if necessary
 | ||||
| install.bin-here: zsh install.bin-@L@ | ||||
| 	$(sdir_top)/mkinstalldirs $(bindir) | ||||
| 	$(INSTALL_PROGRAM) zsh $(bindir)/zsh-$(VERSION) | ||||
| 	$(INSTALL_PROGRAM) $(STRIPFLAGS) zsh $(bindir)/zsh-$(VERSION) | ||||
| 	if test -f $(bindir)/zsh; then \
 | ||||
| 	    rm -f $(bindir)/zsh.old; \
 | ||||
| 	    ln $(bindir)/zsh $(bindir)/zsh.old; \
 | ||||
|  |  | |||
|  | @ -119,8 +119,9 @@ uninstall.modules: uninstall.modules-here | |||
| install.bin-here uninstall.bin-here: | ||||
| 
 | ||||
| install.modules-here: | ||||
| 	$(sdir_top)/mkinstalldirs $(MODDIR) | ||||
| 	modules='$(MODULES)'; for mod in $$modules; do \ | ||||
| 	modules='$(MODULES)'; \ | ||||
| 	if test -n "$$modules"; then $(sdir_top)/mkinstalldirs $(MODDIR); fi; \ | ||||
| 	for mod in $$modules; do \ | ||||
| 	    $(INSTALL_PROGRAM) $$mod $(MODDIR)/$$mod; \ | ||||
| 	done | ||||
| 
 | ||||
|  |  | |||
|  | @ -2945,7 +2945,7 @@ docompletion(char *s, int lst, int incmd) | |||
| 	ainfo = fainfo = NULL; | ||||
| 
 | ||||
| 	/* Make sure we have the completion list and compctl. */ | ||||
| 	if (makecomplist(s, incmd)) { | ||||
| 	if (makecomplist(s, incmd, lst)) { | ||||
| 	    /* Error condition: feeeeeeeeeeeeep(). */ | ||||
| 	    feep(); | ||||
| 	    goto compend; | ||||
|  | @ -3029,7 +3029,7 @@ static unsigned long ccont; | |||
| 
 | ||||
| /**/ | ||||
| static int | ||||
| makecomplist(char *s, int incmd) | ||||
| makecomplist(char *s, int incmd, int lst) | ||||
| { | ||||
|     struct cmlist ms; | ||||
|     Cmlist m = cmatcher; | ||||
|  | @ -3062,7 +3062,7 @@ makecomplist(char *s, int incmd) | |||
| 	ccused = newlinklist(); | ||||
| 	ccstack = newlinklist(); | ||||
| 
 | ||||
| 	makecomplistglobal(s, incmd); | ||||
| 	makecomplistglobal(s, incmd, lst); | ||||
| 
 | ||||
| 	endcmgroup(NULL); | ||||
| 
 | ||||
|  | @ -3098,12 +3098,14 @@ makecomplist(char *s, int incmd) | |||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| makecomplistglobal(char *os, int incmd) | ||||
| makecomplistglobal(char *os, int incmd, int lst) | ||||
| { | ||||
|     Compctl cc; | ||||
|     char *s; | ||||
| 
 | ||||
|     if (inwhat == IN_ENV) | ||||
|     if (lst == COMP_WIDGET) { | ||||
| 	cc = compwidget->u.cc; | ||||
|     } else if (inwhat == IN_ENV) | ||||
|         /* Default completion for parameter values. */ | ||||
|         cc = &cc_default; | ||||
|     else if (inwhat == IN_MATH) { | ||||
|  | @ -4413,7 +4415,8 @@ get_user_var(char *nam) | |||
|     } else { | ||||
| 	/* Otherwise it should be a parameter name. */ | ||||
| 	char **arr = NULL, *val; | ||||
| 	if (!(arr = getaparam(nam)) && (val = getsparam(nam))) { | ||||
| 	if (!(arr = getaparam(nam)) && !(arr = gethparam(nam)) && | ||||
| 	    (val = getsparam(nam))) { | ||||
| 	    arr = (char **)ncalloc(2*sizeof(char *)); | ||||
| 	    arr[0] = val; | ||||
| 	    arr[1] = NULL; | ||||
|  | @ -5026,6 +5029,7 @@ do_single(Cmatch m) | |||
| 		else { | ||||
| 		    p = (char *) ncalloc(strlen(ppre) + strlen(str) + | ||||
| 					 strlen(psuf) + 1); | ||||
| 		    sprintf(p, "%s%s%s", ppre, str, psuf); | ||||
| 		} | ||||
| 		parsestr(p); | ||||
| 		if (ic) | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ static struct builtin builtins[] = | |||
|     BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), | ||||
|     BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL), | ||||
|     BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL), | ||||
|     BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtux", NULL), | ||||
|     BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL), | ||||
|     BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL), | ||||
|     BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL), | ||||
|     BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), | ||||
|  | @ -60,7 +60,7 @@ static struct builtin builtins[] = | |||
|     BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL), | ||||
|     BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL), | ||||
|     BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL), | ||||
|     BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZfilrtu", "x"), | ||||
|     BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"), | ||||
|     BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL), | ||||
|     BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL), | ||||
|     BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), | ||||
|  | @ -78,7 +78,7 @@ static struct builtin builtins[] = | |||
|     BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL), | ||||
|     BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL), | ||||
|     BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL), | ||||
|     BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZilrtu", NULL), | ||||
|     BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL), | ||||
|     BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL), | ||||
|     BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL), | ||||
| 
 | ||||
|  | @ -93,7 +93,7 @@ static struct builtin builtins[] = | |||
|     BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), | ||||
|     BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL), | ||||
|     BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL), | ||||
|     BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfiltux", "r"), | ||||
|     BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"), | ||||
|     BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"), | ||||
|     BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL), | ||||
|     BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL), | ||||
|  | @ -107,7 +107,7 @@ static struct builtin builtins[] = | |||
|     BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL), | ||||
|     BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), | ||||
|     BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), | ||||
|     BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfilrtuxm", NULL), | ||||
|     BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtuxm", NULL), | ||||
|     BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), | ||||
|     BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"), | ||||
|     BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"), | ||||
|  | @ -618,6 +618,8 @@ set_pwd_env(void) | |||
| { | ||||
|     Param pm; | ||||
| 
 | ||||
|     /* update the PWD and OLDPWD shell parameters */ | ||||
| 
 | ||||
|     pm = (Param) paramtab->getnode(paramtab, "PWD"); | ||||
|     if (pm && PM_TYPE(pm->flags) != PM_SCALAR) { | ||||
| 	pm->flags &= ~PM_READONLY; | ||||
|  | @ -704,7 +706,6 @@ bin_cd(char *nam, char **argv, char *ops, int func) | |||
| 	    chdir(unmeta(pwd)); | ||||
| 	} | ||||
|     } | ||||
|     set_pwd_env(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -946,7 +947,6 @@ cd_try_chdir(char *pfix, char *dest, int hard) | |||
| static void | ||||
| cd_new_pwd(int func, LinkNode dir, int chaselinks) | ||||
| { | ||||
|     Param pm; | ||||
|     List l; | ||||
|     char *new_pwd, *s; | ||||
|     int dirstacksize; | ||||
|  | @ -981,13 +981,8 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks) | |||
|     zsfree(oldpwd); | ||||
|     oldpwd = pwd; | ||||
|     pwd = new_pwd; | ||||
|     /* update the PWD and OLDPWD shell parameters */ | ||||
|     if ((pm = (Param) paramtab->getnode(paramtab, "PWD")) && | ||||
| 	(pm->flags & PM_EXPORTED) && pm->env) | ||||
| 	pm->env = replenv(pm->env, pwd); | ||||
|     if ((pm = (Param) paramtab->getnode(paramtab, "OLDPWD")) && | ||||
| 	(pm->flags & PM_EXPORTED) && pm->env) | ||||
| 	pm->env = replenv(pm->env, oldpwd); | ||||
|     set_pwd_env(); | ||||
| 
 | ||||
|     if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE)) | ||||
| 	printdirstack(); | ||||
|     else if (doprintdir) { | ||||
|  | @ -1474,8 +1469,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) | |||
|     Param pm; | ||||
|     Asgment asg; | ||||
|     Comp com; | ||||
|     char *optstr = "iLRZlurtxU"; | ||||
|     int on = 0, off = 0, roff, bit = PM_INTEGER; | ||||
|     char *optstr = "aiLRZlurtxU----A"; | ||||
|     int on = 0, off = 0, roff, bit = PM_ARRAY; | ||||
|     int initon, initoff, of, i; | ||||
|     int returnval = 0, printflags = 0; | ||||
| 
 | ||||
|  | @ -1506,6 +1501,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) | |||
| 	off |= PM_LOWER; | ||||
|     if (on & PM_LOWER) | ||||
| 	off |= PM_UPPER; | ||||
|     if (on & PM_HASHED) | ||||
| 	off |= PM_ARRAY; | ||||
|     on &= ~off; | ||||
| 
 | ||||
|     /* Given no arguments, list whatever the options specify. */ | ||||
|  | @ -1548,8 +1545,15 @@ bin_typeset(char *name, char **argv, char *ops, int func) | |||
| 			    if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) && | ||||
| 				!(pm->flags & PM_READONLY & ~off)) | ||||
| 				uniqarray((*pm->gets.afn) (pm)); | ||||
| 			    if ((on & ~pm->flags) & PM_HASHED) { | ||||
| 				char *nam = ztrdup(pm->nam); | ||||
| 				unsetparam(nam); | ||||
| 				pm = createparam(nam, on & ~PM_READONLY); | ||||
| 				DPUTS(!pm, "BUG: parameter not created"); | ||||
| 			    } | ||||
| 			    pm->flags = (pm->flags | on) & ~off; | ||||
| 			    if (PM_TYPE(pm->flags) != PM_ARRAY) { | ||||
| 			    if (PM_TYPE(pm->flags) != PM_ARRAY && | ||||
| 				PM_TYPE(pm->flags) != PM_HASHED) { | ||||
| 				if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen) | ||||
| 				    pm->ct = auxlen; | ||||
| 				/* did we just export this? */ | ||||
|  | @ -1598,7 +1602,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) | |||
| 	    (((pm->flags & PM_SPECIAL) && pm->level == locallevel) || | ||||
| 	     (!(pm->flags & PM_UNSET) && | ||||
| 	      ((locallevel == pm->level) || func == BIN_EXPORT) && | ||||
| 	      !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)))) { | ||||
| 	      !(bit = (((off & pm->flags) | (on & ~pm->flags)) & | ||||
| 		       (PM_INTEGER|PM_HASHED)))))) { | ||||
| 	    /* if no flags or values are given, just print this parameter */ | ||||
| 	    if (!on && !roff && !asg->value) { | ||||
| 		paramtab->printnode((HashNode) pm, 0); | ||||
|  | @ -1623,7 +1628,8 @@ bin_typeset(char *name, char **argv, char *ops, int func) | |||
| 	    if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && | ||||
| 		auxlen) | ||||
| 		pm->ct = auxlen; | ||||
| 	    if (PM_TYPE(pm->flags) != PM_ARRAY) { | ||||
| 	    if (PM_TYPE(pm->flags) != PM_ARRAY && | ||||
| 		PM_TYPE(pm->flags) != PM_HASHED) { | ||||
| 		if (pm->flags & PM_EXPORTED) { | ||||
| 		    if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value) | ||||
| 			pm->env = addenv(asg->name, getsparam(asg->name)); | ||||
|  |  | |||
							
								
								
									
										22
									
								
								Src/exec.c
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								Src/exec.c
									
										
									
									
									
								
							|  | @ -1004,11 +1004,12 @@ void | |||
| untokenize(char *s) | ||||
| { | ||||
|     for (; *s; s++) | ||||
| 	if (itok(*s)) | ||||
| 	if (itok(*s)) { | ||||
| 	    if (*s == Nularg) | ||||
| 		chuck(s--); | ||||
| 	    else | ||||
| 		*s = ztokens[*s - Pound]; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Open a file for writing redicection */ | ||||
|  | @ -1923,22 +1924,8 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p) | |||
| 	    } else if (!(pm->flags & PM_READONLY) && | ||||
| 		       (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) { | ||||
| 		Param tpm = (Param) alloc(sizeof *tpm); | ||||
| 
 | ||||
| 		tpm->nam = s; | ||||
| 		tpm->flags = pm->flags; | ||||
| 		switch (PM_TYPE(pm->flags)) { | ||||
| 		case PM_SCALAR: | ||||
| 		    tpm->u.str = ztrdup(pm->gets.cfn(pm)); | ||||
| 		    break; | ||||
| 		case PM_INTEGER: | ||||
| 		    tpm->u.val = pm->gets.ifn(pm); | ||||
| 		    break; | ||||
| 		case PM_ARRAY: | ||||
| 		    PERMALLOC { | ||||
| 			tpm->u.arr = arrdup(pm->gets.afn(pm)); | ||||
| 		    } LASTALLOC; | ||||
| 		    break; | ||||
| 		} | ||||
| 		copyparam(tpm, pm, 1); | ||||
| 		pm = tpm; | ||||
| 	    } | ||||
| 	    addlinknode(*remove_p, s); | ||||
|  | @ -1989,6 +1976,9 @@ restore_params(LinkList restorelist, LinkList removelist) | |||
| 		case PM_ARRAY: | ||||
| 		    tpm->sets.afn(tpm, pm->u.arr); | ||||
| 		    break; | ||||
| 		case PM_HASHED: | ||||
| 		    tpm->sets.hfn(tpm, pm->u.hash); | ||||
| 		    break; | ||||
| 		} | ||||
| 	    } else | ||||
| 		paramtab->addnode(paramtab, pm->nam, pm); | ||||
|  |  | |||
							
								
								
									
										19
									
								
								Src/glob.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								Src/glob.c
									
										
									
									
									
								
							|  | @ -355,21 +355,12 @@ scanner(Complist q) | |||
| 	    insert(c->str, 0); | ||||
|     } else { | ||||
| 	/* Do pattern matching on current path section. */ | ||||
| 	char *fn; | ||||
| 	char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; | ||||
| 	int dirs = !!q->next; | ||||
| 	DIR *lock; | ||||
| 	DIR *lock = opendir(fn); | ||||
| 	char *subdirs = NULL; | ||||
| 	int subdirlen = 0; | ||||
| 
 | ||||
| 	fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : "."; | ||||
| 	if (dirs) { | ||||
| 	    struct stat st; | ||||
| 	    stat(fn, &st); | ||||
| 	    /* a directory with subdirectories has link count greater than 2 */ | ||||
| 	    if (!S_ISDIR(st.st_mode) || st.st_nlink == 2) | ||||
| 		return; | ||||
| 	} | ||||
| 	lock = opendir(fn); | ||||
| 	if (lock == NULL) | ||||
| 	    return; | ||||
| 	while ((fn = zreaddir(lock, 1)) && !errflag) { | ||||
|  | @ -594,7 +585,8 @@ parsecomp(int gflag) | |||
| 		 pptr[1] && pptr[1] != Outpar && pptr[1] != Bar) || | ||||
| 		*pptr == Outpar) { | ||||
| 		if (*pptr == '/' || !*pptr || | ||||
| 		    (isset(EXTENDEDGLOB) && *pptr == Tilde && | ||||
| 		    ((*pptr == Bar || | ||||
| 		      (isset(EXTENDEDGLOB) && *pptr == Tilde)) && | ||||
| 		     (gflag & GF_TOPLEV))) | ||||
| 		    c->stat |= C_LAST; | ||||
| 		return c; | ||||
|  | @ -746,7 +738,8 @@ parsecomp(int gflag) | |||
|     } | ||||
|     /* mark if last pattern component in path component or pattern */ | ||||
|     if (*pptr == '/' || !*pptr || | ||||
| 	(isset(EXTENDEDGLOB) && *pptr == Tilde && (gflag & GF_TOPLEV))) | ||||
| 	((*pptr == Bar || | ||||
| 	 (isset(EXTENDEDGLOB) && *pptr == Tilde)) && (gflag & GF_TOPLEV))) | ||||
| 	c->stat |= C_LAST; | ||||
|     c->str = dupstrpfx(cstr, pptr - cstr); | ||||
|     return c; | ||||
|  |  | |||
|  | @ -1061,93 +1061,6 @@ printaliasnode(HashNode hn, int printflags) | |||
|     putchar('\n'); | ||||
| } | ||||
| 
 | ||||
| /**********************************/ | ||||
| /* Parameter Hash Table Functions */ | ||||
| /**********************************/ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| freeparamnode(HashNode hn) | ||||
| { | ||||
|     Param pm = (Param) hn; | ||||
|   | ||||
|     zsfree(pm->nam); | ||||
|     zfree(pm, sizeof(struct param)); | ||||
| } | ||||
| 
 | ||||
| /* Print a parameter */ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| printparamnode(HashNode hn, int printflags) | ||||
| { | ||||
|     Param p = (Param) hn; | ||||
|     char *t, **u; | ||||
| 
 | ||||
|     if (p->flags & PM_UNSET) | ||||
| 	return; | ||||
| 
 | ||||
|     /* Print the attributes of the parameter */ | ||||
|     if (printflags & PRINT_TYPE) { | ||||
| 	if (p->flags & PM_INTEGER) | ||||
| 	    printf("integer "); | ||||
| 	if (p->flags & PM_ARRAY) | ||||
| 	    printf("array "); | ||||
| 	if (p->flags & PM_LEFT) | ||||
| 	    printf("left justified %d ", p->ct); | ||||
| 	if (p->flags & PM_RIGHT_B) | ||||
| 	    printf("right justified %d ", p->ct); | ||||
| 	if (p->flags & PM_RIGHT_Z) | ||||
| 	    printf("zero filled %d ", p->ct); | ||||
| 	if (p->flags & PM_LOWER) | ||||
| 	    printf("lowercase "); | ||||
| 	if (p->flags & PM_UPPER) | ||||
| 	    printf("uppercase "); | ||||
| 	if (p->flags & PM_READONLY) | ||||
| 	    printf("readonly "); | ||||
| 	if (p->flags & PM_TAGGED) | ||||
| 	    printf("tagged "); | ||||
| 	if (p->flags & PM_EXPORTED) | ||||
| 	    printf("exported "); | ||||
|     } | ||||
| 
 | ||||
|     if (printflags & PRINT_NAMEONLY) { | ||||
| 	zputs(p->nam, stdout); | ||||
| 	putchar('\n'); | ||||
| 	return; | ||||
|     } | ||||
| 
 | ||||
|     /* How the value is displayed depends *
 | ||||
|      * on the type of the parameter       */ | ||||
|     quotedzputs(p->nam, stdout); | ||||
|     putchar('='); | ||||
|     switch (PM_TYPE(p->flags)) { | ||||
|     case PM_SCALAR: | ||||
| 	/* string: simple output */ | ||||
| 	if (p->gets.cfn && (t = p->gets.cfn(p))) | ||||
| 	    quotedzputs(t, stdout); | ||||
| 	putchar('\n'); | ||||
| 	break; | ||||
|     case PM_INTEGER: | ||||
| 	/* integer */ | ||||
| 	printf("%ld\n", p->gets.ifn(p)); | ||||
| 	break; | ||||
|     case PM_ARRAY: | ||||
| 	/* array */ | ||||
| 	putchar('('); | ||||
| 	u = p->gets.afn(p); | ||||
| 	if(*u) { | ||||
| 	    quotedzputs(*u++, stdout); | ||||
| 	    while (*u) { | ||||
| 		putchar(' '); | ||||
| 		quotedzputs(*u++, stdout); | ||||
| 	    } | ||||
| 	} | ||||
| 	printf(")\n"); | ||||
| 	break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /****************************************/ | ||||
| /* Named Directory Hash Table Functions */ | ||||
| /****************************************/ | ||||
|  |  | |||
|  | @ -176,7 +176,7 @@ shingetline(void) | |||
| int | ||||
| ingetc(void) | ||||
| { | ||||
|     char lastc; | ||||
|     int lastc; | ||||
| 
 | ||||
|     if (lexstop) | ||||
| 	return ' '; | ||||
|  |  | |||
							
								
								
									
										471
									
								
								Src/params.c
									
										
									
									
									
								
							
							
						
						
									
										471
									
								
								Src/params.c
									
										
									
									
									
								
							|  | @ -232,6 +232,11 @@ IPDEF9("manpath", &manpath, "MANPATH"), | |||
| IPDEF9("psvar", &psvar, "PSVAR"), | ||||
| IPDEF9("watch", &watch, "WATCH"), | ||||
| 
 | ||||
| /*TEST BEGIN*/ | ||||
| #define IPDEF10(A) {NULL,A,PM_HASHED|PM_SPECIAL|PM_DONTIMPORT,BR((void *)0),SFN(hashsetfn),GFN(hashgetfn),stdunsetfn,0,NULL,NULL,NULL,0} | ||||
| IPDEF10("testhash"), | ||||
| /*TEST END*/ | ||||
| 
 | ||||
| #ifdef DYNAMIC | ||||
| IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), | ||||
| #endif | ||||
|  | @ -247,7 +252,137 @@ static Param argvparam; | |||
|   | ||||
| /**/ | ||||
| HashTable paramtab; | ||||
|   | ||||
| 
 | ||||
| /**/ | ||||
| HashTable | ||||
| newparamtable(int size, char const *name) | ||||
| { | ||||
|     HashTable ht = newhashtable(size, name, NULL); | ||||
| 
 | ||||
|     ht->hash        = hasher; | ||||
|     ht->emptytable  = emptyhashtable; | ||||
|     ht->filltable   = NULL; | ||||
|     ht->addnode     = addhashnode; | ||||
|     ht->getnode     = gethashnode2; | ||||
|     ht->getnode2    = gethashnode2; | ||||
|     ht->removenode  = removehashnode; | ||||
|     ht->disablenode = NULL; | ||||
|     ht->enablenode  = NULL; | ||||
|     ht->freenode    = freeparamnode; | ||||
|     ht->printnode   = printparamnode; | ||||
| 
 | ||||
|     return ht; | ||||
| } | ||||
| 
 | ||||
| /* Copy a parameter hash table */ | ||||
| 
 | ||||
| static HashTable outtable; | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| scancopyparams(HashNode hn, int flags) | ||||
| { | ||||
|     /* Going into a real parameter, so always use permanent storage */ | ||||
|     Param pm = (Param)hn; | ||||
|     Param tpm = (Param) zcalloc(sizeof *tpm); | ||||
|     tpm->nam = ztrdup(pm->nam); | ||||
|     copyparam(tpm, pm, 0); | ||||
|     addhashnode(outtable, tpm->nam, tpm); | ||||
| } | ||||
| 
 | ||||
| /**/ | ||||
| HashTable | ||||
| copyparamtable(HashTable ht, char *name) | ||||
| { | ||||
|     HashTable nht = newparamtable(ht->hsize, name); | ||||
|     outtable = nht; | ||||
|     scanhashtable(ht, 0, 0, 0, scancopyparams, 0); | ||||
|     outtable = NULL; | ||||
|     return nht; | ||||
| } | ||||
| 
 | ||||
| #define SCANPM_WANTVALS   (1<<0) | ||||
| #define SCANPM_WANTKEYS   (1<<1) | ||||
| #define SCANPM_WANTINDEX  (1<<2) | ||||
| 
 | ||||
| static unsigned numparamvals; | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| scancountparams(HashNode hn, int flags) | ||||
| { | ||||
|     if (!(((Param)hn)->flags & PM_UNSET)) { | ||||
| 	++numparamvals; | ||||
| 	if ((flags & SCANPM_WANTKEYS) && (flags & SCANPM_WANTVALS)) | ||||
| 	    ++numparamvals; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static char **paramvals; | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| scanparamvals(HashNode hn, int flags) | ||||
| { | ||||
|     struct value v; | ||||
|     v.pm = (Param)hn; | ||||
|     if (!(v.pm->flags & PM_UNSET)) { | ||||
| 	if (flags & SCANPM_WANTKEYS) { | ||||
| 	    paramvals[numparamvals++] = v.pm->nam; | ||||
| 	    if (!(flags & SCANPM_WANTVALS)) | ||||
| 		return; | ||||
| 	} | ||||
| 	v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED)); | ||||
| 	v.inv = (flags & SCANPM_WANTINDEX); | ||||
| 	v.a = 0; | ||||
| 	v.b = -1; | ||||
| 	paramvals[numparamvals++] = getstrvalue(&v); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**/ | ||||
| char ** | ||||
| paramvalarr(HashTable ht, unsigned flags) | ||||
| { | ||||
|     MUSTUSEHEAP("paramvalarr"); | ||||
|     numparamvals = 0; | ||||
|     if (ht) | ||||
| 	scanhashtable(ht, 0, 0, 0, scancountparams, flags); | ||||
|     paramvals = (char **) alloc((numparamvals + 1) * sizeof(char *)); | ||||
|     if (ht) { | ||||
| 	numparamvals = 0; | ||||
| 	scanhashtable(ht, 0, 0, 0, scanparamvals, flags); | ||||
|     } | ||||
|     paramvals[numparamvals] = 0; | ||||
|     return paramvals; | ||||
| } | ||||
| 
 | ||||
| /* Return the full array (no indexing) referred to by a Value. *
 | ||||
|  * The array value is cached for the lifetime of the Value.    */ | ||||
| 
 | ||||
| /**/ | ||||
| static char ** | ||||
| getvaluearr(Value v) | ||||
| { | ||||
|     if (v->arr) | ||||
| 	return v->arr; | ||||
|     else if (PM_TYPE(v->pm->flags) == PM_ARRAY) | ||||
| 	return v->arr = v->pm->gets.afn(v->pm); | ||||
|     else if (PM_TYPE(v->pm->flags) == PM_HASHED) { | ||||
| 	unsigned flags = 0; | ||||
| 	if (v->a) | ||||
| 	    flags |= SCANPM_WANTKEYS; | ||||
| 	if (v->b > v->a) | ||||
| 	    flags |= SCANPM_WANTVALS; | ||||
| 	v->arr = paramvalarr(v->pm->gets.hfn(v->pm), flags); | ||||
| 	/* Can't take numeric slices of associative arrays */ | ||||
| 	v->a = 0; | ||||
| 	v->b = -1; | ||||
| 	return v->arr; | ||||
|     } else | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Set up parameter hash table.  This will add predefined  *
 | ||||
|  * parameter entries as well as setting up parameter table * | ||||
|  * entries for environment variables we inherit.           */ | ||||
|  | @ -261,19 +396,7 @@ createparamtable(void) | |||
|     char buf[50], *str, *iname; | ||||
|     int num_env; | ||||
| 
 | ||||
|     paramtab = newhashtable(151, "paramtab", NULL); | ||||
| 
 | ||||
|     paramtab->hash        = hasher; | ||||
|     paramtab->emptytable  = NULL; | ||||
|     paramtab->filltable   = NULL; | ||||
|     paramtab->addnode     = addhashnode; | ||||
|     paramtab->getnode     = gethashnode2; | ||||
|     paramtab->getnode2    = gethashnode2; | ||||
|     paramtab->removenode  = removehashnode; | ||||
|     paramtab->disablenode = NULL; | ||||
|     paramtab->enablenode  = NULL; | ||||
|     paramtab->freenode    = freeparamnode; | ||||
|     paramtab->printnode   = printparamnode; | ||||
|     paramtab = newparamtable(151, "paramtab"); | ||||
| 
 | ||||
|     /* Add the special parameters to the hash table */ | ||||
|     for (ip = special_params; ip->nam; ip++) | ||||
|  | @ -368,6 +491,36 @@ createparamtable(void) | |||
|     noerrs = 0; | ||||
| } | ||||
| 
 | ||||
| /* assign various functions used for non-special parameters */ | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| assigngetset(Param pm) | ||||
| { | ||||
|     switch (PM_TYPE(pm->flags)) { | ||||
|     case PM_SCALAR: | ||||
| 	pm->sets.cfn = strsetfn; | ||||
| 	pm->gets.cfn = strgetfn; | ||||
| 	break; | ||||
|     case PM_INTEGER: | ||||
| 	pm->sets.ifn = intsetfn; | ||||
| 	pm->gets.ifn = intgetfn; | ||||
| 	break; | ||||
|     case PM_ARRAY: | ||||
| 	pm->sets.afn = arrsetfn; | ||||
| 	pm->gets.afn = arrgetfn; | ||||
| 	break; | ||||
|     case PM_HASHED: | ||||
| 	pm->sets.hfn = hashsetfn; | ||||
| 	pm->gets.hfn = hashgetfn; | ||||
| 	break; | ||||
|     default: | ||||
| 	DPUTS(1, "BUG: tried to create param node without valid flag"); | ||||
| 	break; | ||||
|     } | ||||
|     pm->unsetfn = stdunsetfn; | ||||
| } | ||||
| 
 | ||||
| /* Create a parameter, so that it can be assigned to.  Returns NULL if the *
 | ||||
|  * parameter already exists or can't be created, otherwise returns the     * | ||||
|  * parameter node.  If a parameter of the same name exists in an outer     * | ||||
|  | @ -413,27 +566,51 @@ createparam(char *name, int flags) | |||
| 	pm = (Param) alloc(sizeof *pm); | ||||
|     pm->flags = flags; | ||||
| 
 | ||||
|     if(!(pm->flags & PM_SPECIAL)) { | ||||
| 	switch (PM_TYPE(flags)) { | ||||
|     if(!(pm->flags & PM_SPECIAL)) | ||||
| 	assigngetset(pm); | ||||
|     return pm; | ||||
| } | ||||
| 
 | ||||
| /* Copy a parameter */ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| copyparam(Param tpm, Param pm, int toplevel) | ||||
| { | ||||
|     /*
 | ||||
|      * Note that tpm, into which we're copying, may not be in permanent | ||||
|      * storage.  However, the values themselves are later used directly | ||||
|      * to set the parameter, so must be permanently allocated (in accordance | ||||
|      * with sets.?fn() usage). | ||||
|      */ | ||||
|     PERMALLOC { | ||||
| 	tpm->flags = pm->flags; | ||||
| 	if (!toplevel) | ||||
| 	    tpm->flags &= ~PM_SPECIAL; | ||||
| 	switch (PM_TYPE(pm->flags)) { | ||||
| 	case PM_SCALAR: | ||||
| 	    pm->sets.cfn = strsetfn; | ||||
| 	    pm->gets.cfn = strgetfn; | ||||
| 	    tpm->u.str = ztrdup(pm->gets.cfn(pm)); | ||||
| 	    break; | ||||
| 	case PM_INTEGER: | ||||
| 	    pm->sets.ifn = intsetfn; | ||||
| 	    pm->gets.ifn = intgetfn; | ||||
| 	    tpm->u.val = pm->gets.ifn(pm); | ||||
| 	    break; | ||||
| 	case PM_ARRAY: | ||||
| 	    pm->sets.afn = arrsetfn; | ||||
| 	    pm->gets.afn = arrgetfn; | ||||
| 	    tpm->u.arr = arrdup(pm->gets.afn(pm)); | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    DPUTS(1, "BUG: tried to create param node without valid flag"); | ||||
| 	case PM_HASHED: | ||||
| 	    tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam); | ||||
| 	    break; | ||||
| 	} | ||||
| 	pm->unsetfn = stdunsetfn; | ||||
|     } | ||||
|     return pm; | ||||
|     } LASTALLOC; | ||||
|     /*
 | ||||
|      * If called from inside an associative array, that array is later going | ||||
|      * to be passed as a real parameter, so we need the gets and sets | ||||
|      * functions to be useful.  However, the saved associated array is | ||||
|      * not itself special, so we just use the standard ones. | ||||
|      * This is also why we switch off PM_SPECIAL. | ||||
|      */ | ||||
|     if (!toplevel) | ||||
| 	assigngetset(tpm); | ||||
| } | ||||
| 
 | ||||
| /* Return 1 if the string s is a valid identifier, else return 0. */ | ||||
|  | @ -577,6 +754,23 @@ getarg(char **str, int *inv, Value v, int a2, long *w) | |||
|     singsub(&s); | ||||
| 
 | ||||
|     if (!rev) { | ||||
| 	if (PM_TYPE(v->pm->flags) == PM_HASHED) { | ||||
| 	    HashTable ht = v->pm->gets.hfn(v->pm); | ||||
| 	    if (!ht) { | ||||
| 		ht = newparamtable(17, v->pm->nam); | ||||
| 		v->pm->sets.hfn(v->pm, ht); | ||||
| 	    } | ||||
| 	    if (!(v->pm = (Param) ht->getnode(ht, s))) { | ||||
| 		HashTable tht = paramtab; | ||||
| 		paramtab = ht; | ||||
| 		v->pm = createparam(s, PM_SCALAR|PM_UNSET); | ||||
| 		paramtab = tht; | ||||
| 	    } | ||||
| 	    v->isarr = 0; | ||||
| 	    v->a = 0; | ||||
| 	    *w = v->b = -1; | ||||
| 	    r = isset(KSHARRAYS) ? 1 : 0; | ||||
| 	} else | ||||
| 	if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0)) | ||||
| 	    r++; | ||||
| 	if (word && !v->isarr) { | ||||
|  | @ -799,11 +993,12 @@ getvalue(char **pptr, int bracks) | |||
|     s = t = *pptr; | ||||
|     garr = NULL; | ||||
| 
 | ||||
|     if (idigit(*s)) | ||||
|     if (idigit(*s)) { | ||||
| 	if (bracks >= 0) | ||||
| 	    ppar = zstrtol(s, &s, 10); | ||||
| 	else | ||||
| 	    ppar = *s++ - '0'; | ||||
|     } | ||||
|     else if (iident(*s)) | ||||
| 	while (iident(*s)) | ||||
| 	    s++; | ||||
|  | @ -844,7 +1039,7 @@ getvalue(char **pptr, int bracks) | |||
| 	if (!pm || (pm->flags & PM_UNSET)) | ||||
| 	    return NULL; | ||||
| 	v = (Value) hcalloc(sizeof *v); | ||||
| 	if (PM_TYPE(pm->flags) == PM_ARRAY) | ||||
| 	if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) | ||||
| 	    v->isarr = isvarat ? -1 : 1; | ||||
| 	v->pm = pm; | ||||
| 	v->inv = 0; | ||||
|  | @ -863,12 +1058,12 @@ getvalue(char **pptr, int bracks) | |||
|     *pptr = s; | ||||
|     if (v->a > MAX_ARRLEN || | ||||
| 	v->a < -MAX_ARRLEN) { | ||||
| 	zerr("subscript to %s: %d", (v->a < 0) ? "small" : "big", v->a); | ||||
| 	zerr("subscript too %s: %d", (v->a < 0) ? "small" : "big", v->a); | ||||
| 	return NULL; | ||||
|     } | ||||
|     if (v->b > MAX_ARRLEN || | ||||
| 	v->b < -MAX_ARRLEN) { | ||||
| 	zerr("subscript to %s: %d", (v->b < 0) ? "small" : "big", v->b); | ||||
| 	zerr("subscript too %s: %d", (v->b < 0) ? "small" : "big", v->b); | ||||
| 	return NULL; | ||||
|     } | ||||
|     return v; | ||||
|  | @ -891,11 +1086,12 @@ getstrvalue(Value v) | |||
| 	} | ||||
| 
 | ||||
| 	switch(PM_TYPE(v->pm->flags)) { | ||||
| 	case PM_HASHED: | ||||
| 	case PM_ARRAY: | ||||
| 	    ss = getvaluearr(v); | ||||
| 	    if (v->isarr) | ||||
| 		s = sepjoin(v->pm->gets.afn(v->pm), NULL); | ||||
| 		s = sepjoin(ss, NULL); | ||||
| 	    else { | ||||
| 		ss = v->pm->gets.afn(v->pm); | ||||
| 		if (v->a < 0) | ||||
| 		    v->a += arrlen(ss); | ||||
| 		s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a]; | ||||
|  | @ -913,8 +1109,9 @@ getstrvalue(Value v) | |||
| 	    break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (v->a == 0 && v->b == -1) | ||||
| 	if (v->a == 0 && v->b == -1) { | ||||
| 	    LASTALLOC_RETURN s; | ||||
| 	} | ||||
| 	if (v->a < 0) | ||||
| 	    v->a += strlen(s); | ||||
| 	if (v->b < 0) | ||||
|  | @ -946,7 +1143,7 @@ getarrvalue(Value v) | |||
| 	s[0] = dupstring(buf); | ||||
| 	return s; | ||||
|     } | ||||
|     s = v->pm->gets.afn(v->pm); | ||||
|     s = getvaluearr(v); | ||||
|     if (v->a == 0 && v->b == -1) | ||||
| 	return s; | ||||
|     if (v->a < 0) | ||||
|  | @ -993,6 +1190,7 @@ setstrvalue(Value v, char *val) | |||
| 	zsfree(val); | ||||
| 	return; | ||||
|     } | ||||
|     v->pm->flags &= ~PM_UNSET; | ||||
|     switch (PM_TYPE(v->pm->flags)) { | ||||
|     case PM_SCALAR: | ||||
| 	MUSTUSEHEAP("setstrvalue"); | ||||
|  | @ -1103,17 +1301,25 @@ setarrvalue(Value v, char **val) | |||
| 	freearray(val); | ||||
| 	return; | ||||
|     } | ||||
|     if (PM_TYPE(v->pm->flags) != PM_ARRAY) { | ||||
|     if (PM_TYPE(v->pm->flags) & ~(PM_ARRAY|PM_HASHED)) { | ||||
| 	freearray(val); | ||||
| 	zerr("attempt to assign array value to non-array", NULL, 0); | ||||
| 	return; | ||||
|     } | ||||
|     if (v->a == 0 && v->b == -1) | ||||
| 	(v->pm->sets.afn) (v->pm, val); | ||||
|     else { | ||||
|     if (v->a == 0 && v->b == -1) { | ||||
| 	if (PM_TYPE(v->pm->flags) == PM_HASHED) | ||||
| 	    arrhashsetfn(v->pm, val); | ||||
| 	else | ||||
| 	    (v->pm->sets.afn) (v->pm, val); | ||||
|     } else { | ||||
| 	char **old, **new, **p, **q, **r; | ||||
| 	int n, ll, i; | ||||
| 
 | ||||
| 	if ((PM_TYPE(v->pm->flags) == PM_HASHED)) { | ||||
| 	    freearray(val); | ||||
| 	    zerr("attempt to set slice of associative array", NULL, 0); | ||||
| 	    return; | ||||
| 	} | ||||
| 	if (v->inv && unset(KSHARRAYS)) | ||||
| 	    v->a--, v->b--; | ||||
| 	q = old = v->pm->gets.afn(v->pm); | ||||
|  | @ -1187,6 +1393,20 @@ getaparam(char *s) | |||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* Retrieve an assoc array parameter as an array */ | ||||
| 
 | ||||
| /**/ | ||||
| char ** | ||||
| gethparam(char *s) | ||||
| { | ||||
|     Value v; | ||||
| 
 | ||||
|     if (!idigit(*s) && (v = getvalue(&s, 0)) && | ||||
| 	PM_TYPE(v->pm->flags) == PM_HASHED) | ||||
| 	return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTVALS); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /**/ | ||||
| Param | ||||
| setsparam(char *s, char *val) | ||||
|  | @ -1248,7 +1468,7 @@ setaparam(char *s, char **val) | |||
|     } else { | ||||
| 	if (!(v = getvalue(&s, 1))) | ||||
| 	    createparam(t, PM_ARRAY); | ||||
| 	else if (PM_TYPE(v->pm->flags) != PM_ARRAY && | ||||
| 	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) && | ||||
| 		 !(v->pm->flags & PM_SPECIAL)) { | ||||
| 	    int uniq = v->pm->flags & PM_UNIQUE; | ||||
| 	    unsetparam(t); | ||||
|  | @ -1338,7 +1558,7 @@ unsetparam_pm(Param pm, int altflag, int exp) | |||
|      * is called.  Beyond that, there is an ambiguity:  should   * | ||||
|      * foo() { local bar; unset bar; } make the global bar       * | ||||
|      * available or not?  The following makes the answer "no".   */ | ||||
|     if (locallevel >= pm->level) | ||||
|     if ((locallevel && locallevel >= pm->level) || (pm->flags & PM_SPECIAL)) | ||||
| 	return; | ||||
| 
 | ||||
|     paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */ | ||||
|  | @ -1363,6 +1583,7 @@ stdunsetfn(Param pm, int exp) | |||
|     switch (PM_TYPE(pm->flags)) { | ||||
| 	case PM_SCALAR: pm->sets.cfn(pm, NULL); break; | ||||
| 	case PM_ARRAY:  pm->sets.afn(pm, NULL); break; | ||||
|         case PM_HASHED: pm->sets.hfn(pm, NULL); break; | ||||
|     } | ||||
|     pm->flags |= PM_UNSET; | ||||
| } | ||||
|  | @ -1429,6 +1650,70 @@ arrsetfn(Param pm, char **x) | |||
|     pm->u.arr = x; | ||||
| } | ||||
| 
 | ||||
| /* Function to get value of an association parameter */ | ||||
| 
 | ||||
| /**/ | ||||
| static HashTable | ||||
| hashgetfn(Param pm) | ||||
| { | ||||
|     return pm->u.hash; | ||||
| } | ||||
| 
 | ||||
| /* Flag to freeparamnode to unset the struct */ | ||||
| 
 | ||||
| static int delunset; | ||||
| 
 | ||||
| /* Function to set value of an association parameter */ | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| hashsetfn(Param pm, HashTable x) | ||||
| { | ||||
|     if (pm->u.hash && pm->u.hash != x) { | ||||
| 	/* The parameters in the hash table need to be unset *
 | ||||
| 	 * before being deleted.                             */ | ||||
| 	int odelunset = delunset; | ||||
| 	delunset = 1; | ||||
| 	deletehashtable(pm->u.hash); | ||||
| 	delunset = odelunset; | ||||
|     } | ||||
|     pm->u.hash = x; | ||||
| } | ||||
| 
 | ||||
| /* Function to set value of an association parameter using key/value pairs */ | ||||
| 
 | ||||
| /**/ | ||||
| static void | ||||
| arrhashsetfn(Param pm, char **val) | ||||
| { | ||||
|     /* Best not to shortcut this by using the existing hash table,   *
 | ||||
|      * since that could cause trouble for special hashes.  This way, * | ||||
|      * it's up to pm->sets.hfn() what to do.                         */ | ||||
|     int alen = arrlen(val); | ||||
|     HashTable opmtab = paramtab, ht; | ||||
|     char **aptr = val; | ||||
|     Value v = (Value) hcalloc(sizeof *v); | ||||
|     v->b = -1; | ||||
| 
 | ||||
|     if (alen % 2) { | ||||
| 	freearray(val); | ||||
| 	zerr("bad set of key/value pairs for associative array\n", | ||||
| 	     NULL, 0); | ||||
| 	return; | ||||
|     } | ||||
|     ht = paramtab = newparamtable(17, pm->nam); | ||||
|     while (*aptr) { | ||||
| 	/* The parameter name is ztrdup'd... */ | ||||
| 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET); | ||||
| 	zsfree(*aptr++); | ||||
| 	/* ...but we can use the value without copying. */ | ||||
| 	setstrvalue(v, *aptr++); | ||||
|     } | ||||
|     paramtab = opmtab; | ||||
|     pm->sets.hfn(pm, ht); | ||||
|     free(val);		/* not freearray() */ | ||||
| } | ||||
| 
 | ||||
| /* This function is used as the set function for      *
 | ||||
|  * special parameters that cannot be set by the user. */ | ||||
| 
 | ||||
|  | @ -2189,3 +2474,107 @@ scanendscope(HashNode hn, int flags) | |||
|     if(pm->level > locallevel) | ||||
| 	unsetparam_pm(pm, 0, 0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**********************************/ | ||||
| /* Parameter Hash Table Functions */ | ||||
| /**********************************/ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| freeparamnode(HashNode hn) | ||||
| { | ||||
|     Param pm = (Param) hn; | ||||
|   | ||||
|     /* Since the second flag to unsetfn isn't used, I don't *
 | ||||
|      * know what its value should be.                       */ | ||||
|     if (delunset) | ||||
| 	pm->unsetfn(pm, 1); | ||||
|     zsfree(pm->nam); | ||||
|     zfree(pm, sizeof(struct param)); | ||||
| } | ||||
| 
 | ||||
| /* Print a parameter */ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| printparamnode(HashNode hn, int printflags) | ||||
| { | ||||
|     Param p = (Param) hn; | ||||
|     char *t, **u; | ||||
| 
 | ||||
|     if (p->flags & PM_UNSET) | ||||
| 	return; | ||||
| 
 | ||||
|     /* Print the attributes of the parameter */ | ||||
|     if (printflags & PRINT_TYPE) { | ||||
| 	if (p->flags & PM_INTEGER) | ||||
| 	    printf("integer "); | ||||
| 	else if (p->flags & PM_ARRAY) | ||||
| 	    printf("array "); | ||||
| 	else if (p->flags & PM_HASHED) | ||||
| 	    printf("association "); | ||||
| 	if (p->flags & PM_LEFT) | ||||
| 	    printf("left justified %d ", p->ct); | ||||
| 	if (p->flags & PM_RIGHT_B) | ||||
| 	    printf("right justified %d ", p->ct); | ||||
| 	if (p->flags & PM_RIGHT_Z) | ||||
| 	    printf("zero filled %d ", p->ct); | ||||
| 	if (p->flags & PM_LOWER) | ||||
| 	    printf("lowercase "); | ||||
| 	if (p->flags & PM_UPPER) | ||||
| 	    printf("uppercase "); | ||||
| 	if (p->flags & PM_READONLY) | ||||
| 	    printf("readonly "); | ||||
| 	if (p->flags & PM_TAGGED) | ||||
| 	    printf("tagged "); | ||||
| 	if (p->flags & PM_EXPORTED) | ||||
| 	    printf("exported "); | ||||
|     } | ||||
| 
 | ||||
|     if (printflags & PRINT_NAMEONLY) { | ||||
| 	zputs(p->nam, stdout); | ||||
| 	putchar('\n'); | ||||
| 	return; | ||||
|     } | ||||
| 
 | ||||
|     /* How the value is displayed depends *
 | ||||
|      * on the type of the parameter       */ | ||||
|     quotedzputs(p->nam, stdout); | ||||
|     putchar('='); | ||||
|     switch (PM_TYPE(p->flags)) { | ||||
|     case PM_SCALAR: | ||||
| 	/* string: simple output */ | ||||
| 	if (p->gets.cfn && (t = p->gets.cfn(p))) | ||||
| 	    quotedzputs(t, stdout); | ||||
| 	putchar('\n'); | ||||
| 	break; | ||||
|     case PM_INTEGER: | ||||
| 	/* integer */ | ||||
| 	printf("%ld\n", p->gets.ifn(p)); | ||||
| 	break; | ||||
|     case PM_ARRAY: | ||||
| 	/* array */ | ||||
| 	putchar('('); | ||||
| 	u = p->gets.afn(p); | ||||
| 	if(*u) { | ||||
| 	    quotedzputs(*u++, stdout); | ||||
| 	    while (*u) { | ||||
| 		putchar(' '); | ||||
| 		quotedzputs(*u++, stdout); | ||||
| 	    } | ||||
| 	} | ||||
| 	printf(")\n"); | ||||
| 	break; | ||||
|     case PM_HASHED: | ||||
| 	/* association */ | ||||
| 	putchar('('); | ||||
| 	{ | ||||
|             HashTable ht = p->gets.hfn(p); | ||||
|             if (ht) | ||||
| 		scanhashtable(ht, 0, 0, 0, ht->printnode, 0); | ||||
| 	} | ||||
| 	printf(")\n"); | ||||
| 	break; | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										256
									
								
								Src/prompt.c
									
										
									
									
									
								
							
							
						
						
									
										256
									
								
								Src/prompt.c
									
										
									
									
									
								
							|  | @ -71,6 +71,10 @@ static int bufspc; | |||
| 
 | ||||
| static char *bp; | ||||
| 
 | ||||
| /* Position of the start of the current line in the buffer */ | ||||
| 
 | ||||
| static char *bufline; | ||||
| 
 | ||||
| /* bp1 is an auxilliary pointer into the buffer, which when non-NULL is *
 | ||||
|  * moved whenever the buffer is reallocated.  It is used when data is   * | ||||
|  * being temporarily held in the buffer.                                */ | ||||
|  | @ -81,11 +85,9 @@ static char *bp1; | |||
| 
 | ||||
| static char *fm; | ||||
| 
 | ||||
| /* Current truncation string (metafied), the length at which truncation *
 | ||||
|  * occurs, and the direction in which it occurs.                        */ | ||||
| /* Non-zero if truncating the current segment of the buffer. */ | ||||
| 
 | ||||
| static char *truncstr; | ||||
| static int trunclen, truncatleft; | ||||
| static int trunclen; | ||||
| 
 | ||||
| /* Current level of nesting of %{ / %} sequences. */ | ||||
| 
 | ||||
|  | @ -95,10 +97,6 @@ static int dontcount; | |||
| 
 | ||||
| static char *rstring, *Rstring; | ||||
| 
 | ||||
| /* If non-zero, Inpar, Outpar and Nularg can be added to the buffer. */ | ||||
| 
 | ||||
| static int nonsp; | ||||
| 
 | ||||
| /* Perform prompt expansion on a string, putting the result in a *
 | ||||
|  * permanently-allocated string.  If ns is non-zero, this string * | ||||
|  * may have embedded Inpar and Outpar, which indicate a toggling * | ||||
|  | @ -130,9 +128,8 @@ promptexpand(char *s, int ns, char *rs, char *Rs) | |||
| 
 | ||||
|     rstring = rs; | ||||
|     Rstring = Rs; | ||||
|     nonsp = ns; | ||||
|     fm = s; | ||||
|     bp = buf = zalloc(bufspc = 256); | ||||
|     bp = bufline = buf = zalloc(bufspc = 256); | ||||
|     bp1 = NULL; | ||||
|     trunclen = 0; | ||||
|     putpromptchar(1, '\0'); | ||||
|  | @ -140,6 +137,15 @@ promptexpand(char *s, int ns, char *rs, char *Rs) | |||
|     if(dontcount) | ||||
| 	*bp++ = Outpar; | ||||
|     *bp = 0; | ||||
|     if (!ns) { | ||||
| 	/* If zero, Inpar, Outpar and Nularg should be removed. */ | ||||
| 	for (bp = buf; *bp; bp++) { | ||||
| 	    if (*bp == Meta) | ||||
| 		bp++; | ||||
| 	    else if (*bp == Inpar || *bp == Outpar || *bp == Nularg) | ||||
| 		chuck(bp); | ||||
| 	} | ||||
|     } | ||||
|     return buf; | ||||
| } | ||||
| 
 | ||||
|  | @ -164,7 +170,7 @@ putpromptchar(int doprint, int endchar) | |||
| 		arg = zstrtol(fm, &fm, 10); | ||||
| 	    } | ||||
| 	    if (*fm == '(') { | ||||
| 		int tc; | ||||
| 		int tc, otrunclen; | ||||
| 
 | ||||
| 		if (idigit(*++fm)) { | ||||
| 		    arg = zstrtol(fm, &fm, 10); | ||||
|  | @ -224,6 +230,12 @@ putpromptchar(int doprint, int endchar) | |||
| 		    if (getegid() == arg) | ||||
| 			test = 1; | ||||
| 		    break; | ||||
| 		case 'l': | ||||
| 		    *bp = '\0'; | ||||
| 		    countprompt(bufline, &t0, 0); | ||||
| 		    if (t0 >= arg) | ||||
| 			test = 1; | ||||
| 		    break; | ||||
| 		case 'L': | ||||
| 		    if (shlvl >= arg) | ||||
| 			test = 1; | ||||
|  | @ -249,10 +261,15 @@ putpromptchar(int doprint, int endchar) | |||
| 		if (!*fm || !(sep = *++fm)) | ||||
| 		    return 0; | ||||
| 		fm++; | ||||
| 		/* Don't do the current truncation until we get back */ | ||||
| 		otrunclen = trunclen; | ||||
| 		trunclen = 0; | ||||
| 		if (!putpromptchar(test == 1 && doprint, sep) || !*++fm || | ||||
| 		    !putpromptchar(test == 0 && doprint, ')')) { | ||||
| 		    trunclen = otrunclen; | ||||
| 		    return 0; | ||||
| 		} | ||||
| 		trunclen = otrunclen; | ||||
| 		continue; | ||||
| 	    } | ||||
| 	    if (!doprint) | ||||
|  | @ -377,72 +394,24 @@ putpromptchar(int doprint, int endchar) | |||
| 		tsetcap(TCUNDERLINEEND, 1); | ||||
| 		break; | ||||
| 	    case '[': | ||||
|                 if (idigit(*++fm)) | ||||
|                     trunclen = zstrtol(fm, &fm, 10); | ||||
|                 else | ||||
|                     trunclen = arg; | ||||
|                 if (trunclen) { | ||||
| 		    truncatleft = *fm && *fm != ']' && *fm++ == '<'; | ||||
| 		    bp1 = bp; | ||||
| 		    while (*fm && *fm != ']') { | ||||
| 			if (*fm == '\\' && fm[1]) | ||||
| 			    ++fm; | ||||
| 			addbufspc(1); | ||||
| 			*bp++ = *fm++; | ||||
| 		    } | ||||
| 		    addbufspc(2); | ||||
| 		    if (bp1 == bp) | ||||
| 			*bp++ = '<'; | ||||
|                     *bp = '\0'; | ||||
| 		    zsfree(truncstr); | ||||
|                     truncstr = ztrdup(bp = bp1); | ||||
| 		    bp1 = NULL; | ||||
|                 } else { | ||||
| 		    while (*fm && *fm != ']') { | ||||
| 			if (*fm == '\\' && fm[1]) | ||||
| 			    fm++; | ||||
| 			fm++; | ||||
| 		    } | ||||
| 		} | ||||
| 		if(!*fm) | ||||
| 		    return 0; | ||||
| 		if (idigit(*++fm)) | ||||
| 		    arg = zstrtol(fm, &fm, 10); | ||||
| 		if (!prompttrunc(arg, ']', doprint, endchar)) | ||||
| 		    return *fm; | ||||
| 		break; | ||||
| 	    case '<': | ||||
| 	    case '>': | ||||
| 		if((trunclen = arg)) { | ||||
| 		    char ch = *fm++; | ||||
| 		    truncatleft = ch == '<'; | ||||
| 		    bp1 = bp; | ||||
| 		    while (*fm && *fm != ch) { | ||||
| 			if (*fm == '\\' && fm[1]) | ||||
| 			    ++fm; | ||||
| 			addbufspc(1); | ||||
| 			*bp++ = *fm++; | ||||
| 		    } | ||||
| 		    addbufspc(1); | ||||
|                     *bp = '\0'; | ||||
| 		    zsfree(truncstr); | ||||
|                     truncstr = ztrdup(bp = bp1); | ||||
| 		    bp1 = NULL; | ||||
| 		} else { | ||||
| 		    char ch = *fm++; | ||||
| 		    while(*fm && *fm != ch) { | ||||
| 			if (*fm == '\\' && fm[1]) | ||||
| 			    fm++; | ||||
| 			fm++; | ||||
| 		    } | ||||
| 		} | ||||
| 		if(!*fm) | ||||
| 		    return 0; | ||||
| 		if (!prompttrunc(arg, *fm, doprint, endchar)) | ||||
| 		    return *fm; | ||||
| 		break; | ||||
| 	    case '{': /*}*/ | ||||
| 		if (!dontcount++ && nonsp) { | ||||
| 		if (!dontcount++) { | ||||
| 		    addbufspc(1); | ||||
| 		    *bp++ = Inpar; | ||||
| 		} | ||||
| 		break; | ||||
| 	    case /*{*/ '}': | ||||
| 		if (dontcount && !--dontcount && nonsp) { | ||||
| 		if (dontcount && !--dontcount) { | ||||
| 		    addbufspc(1); | ||||
| 		    *bp++ = Outpar; | ||||
| 		} | ||||
|  | @ -569,7 +538,7 @@ putpromptchar(int doprint, int endchar) | |||
| 		break; | ||||
| 	    } | ||||
| 	} else if(*fm == '!' && isset(PROMPTBANG)) { | ||||
| 	    if(doprint) | ||||
| 	    if(doprint) { | ||||
| 		if(fm[1] == '!') { | ||||
| 		    fm++; | ||||
| 		    addbufspc(1); | ||||
|  | @ -579,6 +548,7 @@ putpromptchar(int doprint, int endchar) | |||
| 		    sprintf(bp, "%d", curhist); | ||||
| 		    bp += strlen(bp); | ||||
| 		} | ||||
| 	    } | ||||
| 	} else { | ||||
| 	    char c = *fm == Meta ? *++fm ^ 32 : *fm; | ||||
| 
 | ||||
|  | @ -604,6 +574,8 @@ pputc(char c) | |||
| 	c ^= 32; | ||||
|     } | ||||
|     *bp++ = c; | ||||
|     if (c == '\n' && !dontcount) | ||||
| 	bufline = bp; | ||||
| } | ||||
| 
 | ||||
| /* Make sure there is room for `need' more characters in the buffer. */ | ||||
|  | @ -627,46 +599,19 @@ addbufspc(int need) | |||
| } | ||||
| 
 | ||||
| /* stradd() adds a metafied string to the prompt, *
 | ||||
|  * in a visible representation, doing truncation. */ | ||||
|  * in a visible representation.                   */ | ||||
| 
 | ||||
| /**/ | ||||
| void | ||||
| stradd(char *d) | ||||
| { | ||||
|     /* dlen is the full length of the string we want to add */ | ||||
|     int dlen = niceztrlen(d); | ||||
|     char *ps, *pd, *pc, *t; | ||||
|     int tlen, maxlen; | ||||
|     addbufspc(dlen); | ||||
|     char *ps, *pc; | ||||
|     addbufspc(niceztrlen(d)); | ||||
|     /* This loop puts the nice representation of the string into the prompt *
 | ||||
|      * buffer.  It might be modified later.  Note that bp isn't changed.    */ | ||||
|     for(ps=d, pd=bp; *ps; ps++) | ||||
|      * buffer.                                                              */ | ||||
|     for(ps=d; *ps; ps++) | ||||
| 	for(pc=nicechar(*ps == Meta ? STOUC(*++ps)^32 : STOUC(*ps)); *pc; pc++) | ||||
| 	    *pd++ = *pc; | ||||
|     if(!trunclen || dlen <= trunclen) { | ||||
| 	/* No truncation is needed, so update bp and return, *
 | ||||
| 	 * leaving the full string in the prompt.            */ | ||||
| 	bp += dlen; | ||||
| 	return; | ||||
|     } | ||||
|     /* We need to truncate.  t points to the truncation string -- which is *
 | ||||
|      * inserted literally, without nice representation.  tlen is its       * | ||||
|      * length, and maxlen is the amout of the main string that we want to  * | ||||
|      * keep.  Note that if the truncation string is longer than the        * | ||||
|      * truncation length (tlen > trunclen), the truncation string is used  * | ||||
|      * in full.                                                            */ | ||||
|     addbufspc(tlen = ztrlen(t = truncstr)); | ||||
|     maxlen = tlen < trunclen ? trunclen - tlen : 0; | ||||
|     if(truncatleft) { | ||||
| 	memmove(bp + strlen(t), bp + dlen - maxlen, maxlen); | ||||
| 	while(*t) | ||||
| 	    *bp++ = *t++; | ||||
| 	bp += maxlen; | ||||
|     } else { | ||||
| 	bp += maxlen; | ||||
| 	while(*t) | ||||
| 	    *bp++ = *t++; | ||||
|     } | ||||
| 	    *bp++ = *pc; | ||||
| } | ||||
| 
 | ||||
| /* tsetcap(), among other things, can write a termcap string into the buffer. */ | ||||
|  | @ -684,12 +629,12 @@ tsetcap(int cap, int flag) | |||
| 	    tputs(tcstr[cap], 1, putshout); | ||||
| 	    break; | ||||
| 	case 1: | ||||
| 	    if (!dontcount && nonsp) { | ||||
| 	    if (!dontcount) { | ||||
| 		addbufspc(1); | ||||
| 		*bp++ = Inpar; | ||||
| 	    } | ||||
| 	    tputs(tcstr[cap], 1, putstr); | ||||
| 	    if (!dontcount && nonsp) { | ||||
| 	    if (!dontcount) { | ||||
| 		int glitch = 0; | ||||
| 
 | ||||
| 		if (cap == TCSTANDOUTBEG || cap == TCSTANDOUTEND) | ||||
|  | @ -764,3 +709,108 @@ countprompt(char *str, int *wp, int *hp) | |||
|     if(hp) | ||||
| 	*hp = h; | ||||
| } | ||||
| 
 | ||||
| /**/ | ||||
| static int | ||||
| prompttrunc(int arg, int truncchar, int doprint, int endchar) | ||||
| { | ||||
|     if (arg) { | ||||
| 	char ch = *fm, *ptr = bp, *truncstr; | ||||
| 	int truncatleft = ch == '<'; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If there is already a truncation active, return so that | ||||
| 	 * can be finished, backing up so that the new truncation | ||||
| 	 * can be started afterwards. | ||||
| 	 */ | ||||
| 	if (trunclen) { | ||||
| 	    while (*--fm != '%') | ||||
| 		; | ||||
| 	    fm--; | ||||
| 	    return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	trunclen = arg; | ||||
| 	if (*fm != ']') | ||||
| 	    fm++; | ||||
| 	while (*fm && *fm != truncchar) { | ||||
| 	    if (*fm == '\\' && fm[1]) | ||||
| 		++fm; | ||||
| 	    addbufspc(1); | ||||
| 	    *bp++ = *fm++; | ||||
| 	} | ||||
| 	if (!*fm) | ||||
| 	    return 0; | ||||
| 	if (bp == ptr && truncchar == ']') { | ||||
| 	    addbufspc(1); | ||||
| 	    *bp++ = '<'; | ||||
| 	} | ||||
| 	truncstr = ztrduppfx(ptr, bp - ptr); | ||||
| 
 | ||||
| 	bp = ptr; | ||||
| 	fm++; | ||||
| 	putpromptchar(doprint, endchar); | ||||
| 	*bp = '\0'; | ||||
| 	if (bp - ptr > trunclen) { | ||||
| 	    /*
 | ||||
| 	     * We need to truncate.  t points to the truncation string -- * | ||||
| 	     * which is inserted literally, without nice representation.  * | ||||
| 	     * tlen is its length, and maxlen is the amount of the main	  * | ||||
| 	     * string that we want to keep.  Note that if the truncation  * | ||||
| 	     * string is longer than the truncation length (tlen >	  * | ||||
| 	     * trunclen), the truncation string is used in full.	  * | ||||
| 	     */ | ||||
| 	    char *t = truncstr; | ||||
| 	    int fullen = bp - ptr; | ||||
| 	    int tlen = ztrlen(t), maxlen; | ||||
| 	    if (tlen > fullen) { | ||||
| 		addbufspc(tlen - fullen); | ||||
| 		bp += tlen - fullen; | ||||
| 	    } else | ||||
| 		bp -= fullen - trunclen; | ||||
| 	    maxlen = tlen < trunclen ? trunclen - tlen : 0; | ||||
| 	    if (truncatleft) { | ||||
| 		if (maxlen) | ||||
| 		    memmove(ptr + strlen(t), ptr + fullen - maxlen, | ||||
| 			    maxlen); | ||||
| 		while (*t) | ||||
| 		    *ptr++ = *t++; | ||||
| 	    } else { | ||||
| 		ptr += maxlen; | ||||
| 		while (*t) | ||||
| 		    *ptr++ = *t++; | ||||
| 	    } | ||||
| 	} | ||||
| 	zsfree(truncstr); | ||||
| 	trunclen = 0; | ||||
| 	/*
 | ||||
| 	 * We may have returned early from the previous putpromptchar * | ||||
| 	 * because we found another truncation following this one.    * | ||||
| 	 * In that case we need to do the rest now.                   * | ||||
| 	 */ | ||||
| 	if (!*fm) | ||||
| 	    return 0; | ||||
| 	if (*fm != endchar) { | ||||
| 	    fm++; | ||||
| 	    /*
 | ||||
| 	     * With trunclen set to zero, we always reach endchar * | ||||
| 	     * (or the terminating NULL) this time round.         * | ||||
| 	     */ | ||||
| 	    if (!putpromptchar(doprint, endchar)) | ||||
| 		return 0; | ||||
| 	    /* Now we have to trick it into matching endchar again */ | ||||
| 	    fm--; | ||||
| 	} | ||||
|     } else { | ||||
| 	if (*fm != ']') | ||||
| 	    fm++; | ||||
| 	while(*fm && *fm != truncchar) { | ||||
| 	    if (*fm == '\\' && fm[1]) | ||||
| 		fm++; | ||||
| 	    fm++; | ||||
| 	} | ||||
| 	if (trunclen || !*fm) | ||||
| 	    return 0; | ||||
|     } | ||||
|     return 1; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										30
									
								
								Src/subst.c
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								Src/subst.c
									
										
									
									
									
								
							|  | @ -716,6 +716,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
|     int eval = 0; | ||||
|     int nojoin = 0; | ||||
|     char inbrace = 0;		/* != 0 means ${...}, otherwise $... */ | ||||
|     char hkeys = 0;		/* 1 means get keys from associative array */ | ||||
|     char hvals = 1;		/* > hkeys get values of associative array */ | ||||
| 
 | ||||
|     *s++ = '\0'; | ||||
|     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' && | ||||
|  | @ -732,12 +734,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
|     if (*s == Inbrace) { | ||||
| 	inbrace = 1; | ||||
| 	s++; | ||||
| 	if (*s == '(' || *s == Inpar) { | ||||
| 	if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) { | ||||
| 	    hkeys = 1; | ||||
| 	    s++; | ||||
| 	} else if (*s == '(' || *s == Inpar) { | ||||
| 	    char *t, sav; | ||||
| 	    int tt = 0; | ||||
| 	    long num; | ||||
| 	    int escapes = 0; | ||||
| 	    int klen; | ||||
| #define UNTOK(C)  (itok(C) ? ztokens[(C) - Pound] : (C)) | ||||
| #define UNTOK_AND_ESCAPE(X) {\ | ||||
| 		untokenize(X = dupstring(s + 1));\ | ||||
| 		if (escapes) {\ | ||||
|  | @ -851,7 +857,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
| 			prenum = num; | ||||
| 		    else | ||||
| 			postnum = num; | ||||
| 		    if (s[1] != sav) | ||||
| 		    if (UNTOK(s[1]) != UNTOK(sav)) | ||||
| 			break; | ||||
| 		    t = get_strarg(++s); | ||||
| 		    if (!*t) | ||||
|  | @ -865,7 +871,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
| 		    *t = sav; | ||||
| 		    sav = *s; | ||||
| 		    s = t + 1; | ||||
| 		    if (*s != sav) { | ||||
| 		    if (UNTOK(*s) != UNTOK(sav)) { | ||||
| 			s--; | ||||
| 			break; | ||||
| 		    } | ||||
|  | @ -886,6 +892,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
| 		    escapes = 1; | ||||
| 		    break; | ||||
| 
 | ||||
| 		case 'k': | ||||
| 		    hkeys = 1; | ||||
| 		    break; | ||||
| 		case 'v': | ||||
| 		    hvals = 2; | ||||
| 		    break; | ||||
| 
 | ||||
| 		default: | ||||
| 		  flagerr: | ||||
| 		    zerr("error in flags", NULL, 0); | ||||
|  | @ -986,9 +999,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | |||
| 	    if (getindex(&s, v) || s == os) | ||||
| 		break; | ||||
| 	} | ||||
| 	if ((isarr = v->isarr)) | ||||
| 	if ((isarr = v->isarr)) { | ||||
| 	    /* No way to reach here with v->inv != 0, so getvaluearr() *
 | ||||
| 	     * will definitely be called by getarrvalue().  Slicing of * | ||||
| 	     * associations isn't done, so use v->a and v->b for flags */ | ||||
| 	    if (PM_TYPE(v->pm->flags) == PM_HASHED) { | ||||
| 		v->a = hkeys; | ||||
| 		v->b = hvals; | ||||
| 	    } | ||||
| 	    aval = getarrvalue(v); | ||||
| 	else { | ||||
| 	} else { | ||||
| 	    if (v->pm->flags & PM_ARRAY) { | ||||
| 		int tmplen = arrlen(v->pm->gets.afn(v->pm)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -450,6 +450,8 @@ getsimptext(Cmd cmd) | |||
| 	    taddchr('('); | ||||
| 	    taddlist(v->arr); | ||||
| 	    taddstr(") "); | ||||
| 	} else if (PM_TYPE(v->type) == PM_HASHED) { | ||||
| 	    /* XXX */ | ||||
| 	} else { | ||||
| 	    taddstr(v->str); | ||||
| 	    taddchr(' '); | ||||
|  |  | |||
|  | @ -510,8 +510,8 @@ adduserdir(char *s, char *t, int flags, int always) | |||
|     if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s)) | ||||
| 	return; | ||||
| 
 | ||||
|     /* Never hash PWD, because it's never useful */ | ||||
|     if (!strcmp(s, "PWD")) | ||||
|     /* Never hash PWD unless it was explicitly requested */ | ||||
|     if (!always && !strcmp(s, "PWD")) | ||||
| 	return; | ||||
| 
 | ||||
|     /* Normal parameter assignments generate calls to this function, *
 | ||||
|  |  | |||
|  | @ -59,6 +59,7 @@ freeheap | |||
| getaparam | ||||
| gethashnode | ||||
| gethashnode2 | ||||
| gethparam | ||||
| getiparam | ||||
| getkeystring | ||||
| getlinknode | ||||
|  |  | |||
|  | @ -538,6 +538,7 @@ struct value { | |||
|     int inv;		/* should we return the index ?        */ | ||||
|     int a;		/* first element of array slice, or -1 */ | ||||
|     int b;		/* last element of array slice, or -1  */ | ||||
|     char **arr;		/* cache for hash turned into array */ | ||||
| }; | ||||
| 
 | ||||
| /* structure for foo=bar assignments */ | ||||
|  | @ -813,6 +814,7 @@ struct param { | |||
| 	char **arr;		/* value if declared array   (PM_ARRAY)   */ | ||||
| 	char *str;		/* value if declared string  (PM_SCALAR)  */ | ||||
| 	long val;		/* value if declared integer (PM_INTEGER) */ | ||||
|         HashTable hash;		/* value if declared assoc   (PM_HASHED)  */ | ||||
|     } u; | ||||
| 
 | ||||
|     /* pointer to function to set value of this parameter */ | ||||
|  | @ -820,6 +822,7 @@ struct param { | |||
| 	void (*cfn) _((Param, char *)); | ||||
| 	void (*ifn) _((Param, long)); | ||||
| 	void (*afn) _((Param, char **)); | ||||
|         void (*hfn) _((Param, HashTable)); | ||||
|     } sets; | ||||
| 
 | ||||
|     /* pointer to function to get value of this parameter */ | ||||
|  | @ -827,6 +830,7 @@ struct param { | |||
| 	char *(*cfn) _((Param)); | ||||
| 	long (*ifn) _((Param)); | ||||
| 	char **(*afn) _((Param)); | ||||
|         HashTable (*hfn) _((Param)); | ||||
|     } gets; | ||||
| 
 | ||||
|     /* pointer to function to unset this parameter */ | ||||
|  | @ -845,8 +849,9 @@ struct param { | |||
| #define PM_SCALAR	0	/* scalar                                     */ | ||||
| #define PM_ARRAY	(1<<0)	/* array                                      */ | ||||
| #define PM_INTEGER	(1<<1)	/* integer                                    */ | ||||
| #define PM_HASHED	(1<<15)	/* association                                */ | ||||
| 
 | ||||
| #define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY)) | ||||
| #define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED)) | ||||
| 
 | ||||
| #define PM_LEFT		(1<<2)	/* left justify and remove leading blanks     */ | ||||
| #define PM_RIGHT_B	(1<<3)	/* right justify and fill with leading blanks */ | ||||
|  |  | |||
							
								
								
									
										6
									
								
								config.guess
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								config.guess
									
										
									
									
										vendored
									
									
								
							|  | @ -557,6 +557,12 @@ EOF | |||
|                            # says <Richard.M.Bartel@ccMail.Census.GOV> | ||||
|         echo i586-unisys-sysv4 | ||||
|         exit 0 ;; | ||||
|     Power*:Rhapsody:*:*) | ||||
|         echo powerpc-apple-rhapsody${UNAME_RELEASE} | ||||
|         exit 0 ;; | ||||
|     *:Rhapsody:*:*) | ||||
|         echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} | ||||
|         exit 0 ;; | ||||
| esac | ||||
| 
 | ||||
| #echo '(No uname command or uname output not recognized.)' 1>&2 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								config.sub
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								config.sub
									
										
									
									
										vendored
									
									
								
							|  | @ -689,7 +689,7 @@ case $os in | |||
| 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | ||||
| 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | ||||
| 	      | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | ||||
| 	      | -linux* | -uxpv*) | ||||
| 	      | -linux* | -uxpv* | -rhapsody* ) | ||||
| 	# Remember, each alternative MUST END IN *, to match a version number. | ||||
| 		;; | ||||
| 	-sunos5*) | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ patches.  (The version number built into the shell has not been changed.) | |||
| 
 | ||||
| Zoli's AIX dynamic loading patch from 3933, slightly updated, without | ||||
| some hunks which weren't needed on AIX 3.x so I don't know how to | ||||
| update properly. | ||||
| update them properly | ||||
| 
 | ||||
| My completion widgets patch | ||||
| 
 | ||||
|  | @ -18,24 +18,85 @@ My patch in 4477 to rename three functions to avoid clashes when | |||
| dynamic loading (particularly necessary on IRIX and AIX), including | ||||
| the effect of Sven's additional fix in 4488 | ||||
| 
 | ||||
| My patch 4513 for case-insensitive globbing via flags, plus fixlet 4552 | ||||
| Sven's magna opera patch-or 4510 and patch-match 4509 to add control | ||||
| of alternative matches and arbitrary mapping between characters in the | ||||
| command line and the matched string, plus all known related fixes | ||||
| 4526, 4527, 4534, 4555, 4557 | ||||
| 
 | ||||
| Sven's magna opera patch-or 4510 and patch-match 4509 to add control of | ||||
| alternative matches and arbitrary mapping between characters in the | ||||
| command line and the matched, plus all known fixes 4526, 4527, 4534, | ||||
| 4555, 4557 | ||||
| My patch 4513 for case-insensitive globbing via flags, plus fixlet 4552 | ||||
| 
 | ||||
| My ~PWD patch 4533 | ||||
| 
 | ||||
| My suggestion for fixing the suffix on a yank in 4564 | ||||
| 
 | ||||
| Bart's deltochar patch including new flags to allow commands not to | ||||
| interrupt cumulative effects in 4570 | ||||
| interrupt cumulative effects in 4570 (new flag merged with compctl | ||||
| widgets flags). | ||||
| 
 | ||||
| Bart's doc fiz 4574 | ||||
| Bart's doc fix 4574 | ||||
| 
 | ||||
| Sven's latest word on the fixsuffix() horror in 4576, plus a | ||||
| fixsuffix() added by hand in delcharorlist() which I've somehow missed | ||||
| along the way | ||||
| A fixsuffix() added by hand in delcharorlist() which I've somehow | ||||
| missed along the way. The fixsuffix() horror is probably not yet | ||||
| resolved; 4576 has side effects and hasn't been applied. | ||||
| 
 | ||||
| My latest version of lete2ctl, not posted | ||||
| My latest version of lete2ctl, not posted but available at | ||||
| http://www.ifh.de/~pws/computing/lete2ctl . | ||||
| 
 | ||||
| Bart's chpwd() fix 4589 | ||||
| 
 | ||||
|   Second edition | ||||
| 
 | ||||
| Added line in zle_tricky.c missed when patching by hand, spotted by | ||||
| Bart.  (Whitespace is still non-canonical.) | ||||
| 
 | ||||
| Fixed up my compctl widgets patch for use with Sven's rewrite, which I | ||||
| hadn't done properly before. | ||||
| 
 | ||||
| Bart's function fixes, 4471 | ||||
| 
 | ||||
| Bart's doc fixes, 4472 | ||||
| 
 | ||||
| Bart's PWD and OLDPWD reshuffle, 4589 | ||||
| 
 | ||||
| My test-line-length patch for prompts, 4591 | ||||
| 
 | ||||
| Configure patch from Wilfredo Sanchez in 4594, with some extra | ||||
| tabbification and without the setterm() hunk, since I've already renamed | ||||
| that to zsetterm(), avoiding the conflict | ||||
| 
 | ||||
| My globbing fix for a bug which shows up in `case' constructs, 4595 | ||||
| 
 | ||||
| Alternative version of the ~PWD patch (allow users to hash PWD | ||||
| explicitly if that's what turns them on), 4596 | ||||
| 
 | ||||
| Bart's experimental associative array patch, 4598, plus various | ||||
| additions, 4599, 4602, 4608, 4641, 4653, 4654.  No documentation yet; | ||||
| if you want to play with this, so far: | ||||
| % typeset -A hash                    # create associative array $hash | ||||
| % hash[one]=eins hash[two]=zwei      # assign elements | ||||
| % hash=(one eins two zwei)           # same, assign whole array (*) | ||||
| % print $hash[one]                   # retrieve elements | ||||
| eins | ||||
| % print $hash                        # whole array looks like normal array | ||||
| eins zwei | ||||
| % print ${(k)hash}                   # flag to get keys | ||||
| one two | ||||
| % print ${(kv)hash}                  # flag to get keys and values (**) | ||||
| one eins two zwei | ||||
| Comparison of (*) and (**) will reveal how to copy an associative | ||||
| array, but you always need to declare it with typeset -A or an | ||||
| ordinary array will appear.  There is a predefined special associative | ||||
| array $testhash, for testing purposes only, which will eventually | ||||
| disappear. | ||||
| 
 | ||||
| My rewrite of prompt truncation, 4601 | ||||
| 
 | ||||
| Bart's params error message fix, 4606 | ||||
| 
 | ||||
| My input fix for 8 bit characters, 4612 | ||||
| 
 | ||||
| Bart's version of the *** fix, 4624 | ||||
| 
 | ||||
| Bart's parameter substitution flag delimiter fix, 4644 | ||||
| 
 | ||||
| My special parameter unset fix, 4662 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue