* Re: special/readonly variables in sh emulation @ 2002-04-03 14:57 Oliver Kiddle 0 siblings, 0 replies; 11+ messages in thread From: Oliver Kiddle @ 2002-04-03 14:57 UTC (permalink / raw) To: zsh-workers Bart wrote: > > } Should we allow attributes like uppercase and integer to apply across > } an array like in ksh (this is messier for hashes as each element has > } its own param)? > > I don't know what the ksh implementation of this is like -- does it apply > the conversion at fetch time, or at assign time? Assign time it seems - fetch time would be better in my opinion. The ksh feature which I was refering to and which I like is: $ a=(one two three) $ typeset -u a $ echo ${a[@]} ONE TWO THREE And similarly for other typeset options such as -i. And thanks for answering the various questions. > The way I would structure this is: > > The lowest-level API provides functions to set and get scalars (strings, > ints, etc.), arrays, array elements, and associative array elements > (including getting the keys or values). > > An intermediate API provides functions implemented in terms of the above > to set and get string ranges, array slices, and arrays of associative > array elements. Special parameters have the option of implementing only > the lowest-level API and using the functions from the intermediate one, > or of providing the intermediate ones for efficiency or other effects. Ok, that is roughly what the patch I posted was heading towards though I'm entirely happy with it. To support the specials overriding the intermediate API you get a fairly big method table. Simple specials would use the default methods. Unless anyone can think of a better system than the method tables or come up with a better, more generic version of the paramdef struct system for setting up specials? > The complication arises when we add in nested substitutions, where the > result of an inner substitution has to be treated as a parameter value > for purposes of outer substitutions. I suggest we actually create a > dummy parameter in this case rather than trying to handle everything via > manipulation of the Value structure -- but that means some pretty heavy > rewriting of paramsubst() and getarg(). A dummy param might be good. I was sort of hoping to get rid of the value struct and use start/end ints where necessary but another option might be a dummy param there to. > If we did create a dummy parameter, we could even give it a name and > let the surrounding substitutions refer to it explicitly, e.g.: > > ... ${$(some command):+blah blah $_ blah blah} ... That's an interesting idea. > I haven't looked at your patch in detail yet, but these seems like things > that could go in the optional intermediate-level API. It would be useful if someone could look at it just a little bit. What I'm least sure of is what is needed to support associative specials properly. I've not done anything on this since last week - I was away for the Easter bank holidays. Oliver This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* special/readonly variables in sh emulation @ 2002-03-18 12:56 Oliver Kiddle 2002-03-18 14:07 ` Peter Stephenson 0 siblings, 1 reply; 11+ messages in thread From: Oliver Kiddle @ 2002-03-18 12:56 UTC (permalink / raw) To: zsh-workers I've recently set /bin/sh to be zsh on my Debian Linux box to see what if any problems occur. The only problem with the init scripts was this: /etc/rcS.d/S45mountnfs.sh:29: options: attempt to set slice of associative array The offending line is: while read device mountpt fstype options Everything else was fine including several configure scripts until I tried to configure, of all things, zsh: ./configure:10594: functions: attempt to set slice of associative array We perhaps ought to rethink the status of any special variables in sh emulation mode. Especially those which are autoloaded out of places like zsh/parameter. Any ideas on how to solve this? Oliver -- This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-18 12:56 Oliver Kiddle @ 2002-03-18 14:07 ` Peter Stephenson 2002-03-18 15:41 ` Oliver Kiddle 0 siblings, 1 reply; 11+ messages in thread From: Peter Stephenson @ 2002-03-18 14:07 UTC (permalink / raw) To: Zsh hackers list Oliver Kiddle wrote: > We perhaps ought to rethink the status of any special variables > in sh emulation mode. Especially those which are autoloaded out of > places like zsh/parameter. Any ideas on how to solve this? Yes, this looks like a big compatibility problem if it's happening in sh mode. I guess the problem is `load=yes' in zleparameter.mdd --- if it wasn't always loaded there would be no problem. Is it just enough to set that to `no' and make zle load it when it needs to run a widget? (If you're using zle or completion widgets, all bets about compatibility are off.) If so, we can forget the more sophisticated solutions below which I wrote before that occurred to me. One way would be to track dependency information better. zsh/parameter is loaded by default because zle needs it. zle itself is not used in a non-interactive shell. So unless the user has directly registered an interest in zsh/parameter we shouldn't load it until we need zle. Another is to shift this sort of parameter into a namespace, as we've been planning for a long time. I think Sven had a way of doing this simply by allowing dots in parameter names --- it wasn't a fully featured namespace implementation, but it might be close enough to allow us to go over to that if anybody had the time to write it. Another is to restrict visibility of zsh/parameter to zle somehow unless the user has asked for it explicitly. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Science Park, Milton Road, Cambridge, CB4 0WH, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-18 14:07 ` Peter Stephenson @ 2002-03-18 15:41 ` Oliver Kiddle 2002-03-19 1:43 ` Bart Schaefer 2002-03-19 11:27 ` Peter Stephenson 0 siblings, 2 replies; 11+ messages in thread From: Oliver Kiddle @ 2002-03-18 15:41 UTC (permalink / raw) To: zsh-workers Peter wrote: > I guess the problem is `load=yes' in zleparameter.mdd --- if it wasn't > always loaded there would be no problem. Is it just enough to set that > to `no' and make zle load it when it needs to run a widget? (If you're > using zle or completion widgets, all bets about compatibility are off.) > One way would be to track dependency information better. zsh/parameter > is loaded by default because zle needs it. zle itself is not used in a > non-interactive shell. So unless the user has directly registered an > interest in zsh/parameter we shouldn't load it until we need zle. >From what I understand, zsh/parameter isn't loaded but we have the equivalent of zmodload -ap for all it's parameters done somewhere. I'm not sure that it is particularly connected to zle. We could limit this autoloading to interactive shells or skip it in sh emulation. As a short term solution and for 4.0, something like this is probably the best way to go and I think we should do it regardless of any longer term ideas like namespaces. Another thing to consider is that because the parameters in zsh/parameter are readonly, we could get the parameter autoloading to allow the parameter to be assigned to without loading the module and then be used - this would solve both the cases I mentioned. Only reading from the parameter without first assigning would do the autoload. > Another is to shift this sort of parameter into a namespace, as we've > been planning for a long time. I think Sven had a way of doing this > simply by allowing dots in parameter names --- it wasn't a fully > featured namespace implementation, but it might be close enough to allow The compound (hierarchical) parameters feature of ksh93 is exactly this - a hack to allow dots in a parameter name. I think this is a mistake because you lose the connection between parameters sharing a common parent. This means that you can't do things like unset a whole hierarchy by unsetting the parent. Some of these problems led on to the unfinished namespace idea in ksh93. Compound variables could be implemented better by being like associative arrays - the parent is a hash table of the elements the only difference being the elements can be any type, and the syntax is different. This alone wouldn't be hard to add onto the existing parameter code. It still needs further thought on my part but I think it would be possible to merge the concepts of namespaces and hierarchical variables by using lexical constructs to decide when to do things like copy-on-read for parent variables. > featured namespace implementation, but it might be close enough to allow > us to go over to that if anybody had the time to write it. Depends on what you mean by having time - in each day I don't have much free but if I start working on the parameter stuff, I'll get there eventually. So to start this off, if we start by getting together a list of: 1. what we think is wrong with the current implementation 2. what it has got right and should be preserved, 3. what new features we might want to support 4. any ideas for the implementation, in particular on the data structure and the interface. 5. anything else I'd prefer to get it right but if the consensus is in favour of something quicker and dirtier then fine. Also, am I right that we *need* a=() to assign an empty array? In ksh, this is how you define something as a compound variable parent which I'd prefer to have done with typeset. Oliver This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-18 15:41 ` Oliver Kiddle @ 2002-03-19 1:43 ` Bart Schaefer 2002-03-20 12:55 ` Oliver Kiddle 2002-03-19 11:27 ` Peter Stephenson 1 sibling, 1 reply; 11+ messages in thread From: Bart Schaefer @ 2002-03-19 1:43 UTC (permalink / raw) To: zsh-workers On Mon, 18 Mar 2002, Oliver Kiddle wrote: > We perhaps ought to rethink the status of any special variables > in sh emulation mode. Especially those which are autoloaded out of > places like zsh/parameter. Any ideas on how to solve this? My suggestion would be simply to disable module autoloading entirely when in sh emulation mode (and maybe ksh too). A sh/ksh script can't possibly be expecting a dynamically loaded module, and "compinit" et al. can load anything they explicitly need. A slightly less drastic approach might be to disable autoloading only for non-interactive sh emulation. On Mon, 18 Mar 2002, Peter Stephenson wrote: > Another is to shift this sort of parameter into a namespace, as we've > been planning for a long time. I think Sven had a way of doing this > simply by allowing dots in parameter names --- it wasn't a fully > featured namespace implementation, but it might be close enough to allow > us to go over to that if anybody had the time to write it. I've fooled around with this a bit. The problem is that you have to allow the dots only inside ${...}, because lots of things break if $file.ext is interpreted as ${file.ext} rather than ${file}.ext. This is a little tricky to acheive, because there'd need to be different typtab[] flags for lexing inside braces v. outside. On Mon, 18 Mar 2002, Oliver Kiddle wrote: > Compound variables could be implemented better by being like > associative arrays - the parent is a hash table of the elements the > only difference being the elements can be any type, and the syntax is > different. This alone wouldn't be hard to add onto the existing > parameter code. In fact, I deliberately used full parameter hash tables for the associative array implementation precisely so they could be extended in the future to support elements of any type. What's needed is a sensible reference and assignment syntax. > Also, am I right that we *need* a=() to assign an empty array? No; `set -A a' will do it. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-19 1:43 ` Bart Schaefer @ 2002-03-20 12:55 ` Oliver Kiddle 2002-03-20 13:53 ` Peter Stephenson 0 siblings, 1 reply; 11+ messages in thread From: Oliver Kiddle @ 2002-03-20 12:55 UTC (permalink / raw) To: zsh-workers Bart wrote: > > My suggestion would be simply to disable module autoloading entirely when > in sh emulation mode (and maybe ksh too). A sh/ksh script can't possibly > be expecting a dynamically loaded module, and "compinit" et al. can load > anything they explicitly need. That seems like a good plan to me. Perhaps excepting any module autoloads explicitly defined by the user with zmodload. > A slightly less drastic approach might be to disable autoloading only for > non-interactive sh emulation. I'm not sure that would gain anything and it can make it confusing or hard to debug when interactive and non-interactive behaviour vary. > On Mon, 18 Mar 2002, Peter Stephenson wrote: > > > Another is to shift this sort of parameter into a namespace, as we've > > been planning for a long time. I think Sven had a way of doing this > > simply by allowing dots in parameter names --- it wasn't a fully Has anyone got a message number for that. I don't remember it. > I've fooled around with this a bit. The problem is that you have to allow > the dots only inside ${...}, because lots of things break if $file.ext is > interpreted as ${file.ext} rather than ${file}.ext. This is a little > tricky to acheive, because there'd need to be different typtab[] flags for > lexing inside braces v. outside. You would also have to cope with what things like .a..b mean. This again shows why I think it is not a good idea to just allow dots in identifiers. It should think of the references as <identifier>.<identifier> and not as just <identifier>. This is important with things like namerefs where it has to resolve each identifier separately. > On Mon, 18 Mar 2002, Oliver Kiddle wrote: > > Compound variables could be implemented better by being like > > associative arrays - the parent is a hash table of the elements the > In fact, I deliberately used full parameter hash tables for the > associative array implementation precisely so they could be extended in > the future to support elements of any type. What's needed is a sensible > reference and assignment syntax. You were very wise then. I can't think of any better assignment or reference syntax than ksh's. Implementing the nested assignments could be defered until later. > > Also, am I right that we *need* a=() to assign an empty array? > > No; `set -A a' will do it. Hm, not as nice though. Peter wrote: > > Oliver Kiddle wrote: > > So to start this off, if we start by getting together a list of: > > 1. what we think is wrong with the current implementation > > 2. what it has got right and should be preserved, > > 3. what new features we might want to support > > 4. any ideas for the implementation, in particular on the data > > structure and the interface. > > 5. anything else > > What's wrong is that it's all very messy; there is a dense hierarchy of Okay, we're agreed on the problem then. Following paragraphs also made sense. > Unfortunately there are dozens of different things you can do with > parameters: The whole complexity of parameters makes me think that we need to evolve it into something better instead of ditching and rewriting. How complete is the test suite for parameters? My implementation idea is to take the param struct, get rid of sets, gets and unsetfn from it and add a new pointer to a method table. The method table would contain a list of function pointers. These functions would be the "uniformly defined entry points". It should be possible to implement a special by overriding the default versions of these functions. Initially, I would replace the gets, sets and unsetfn with functions which pass particular types such as arrays, integers etc. Calling the array set for an integer would change the parameter's type. The get functions would not change the parameter but would do a conversion to return the requested type - much as you described with your contexts suggestion. I could then add more functions to the method table bit by bit to move more functionality in. Does that approach sound reasonable? > - handle quoting, e.g. what a scalar does with an array slice may > depend on whether it is in quotes I can't think of an example of this but this and areas like the value struct is where I have fewer ideas on implementation. > Very likely any consistent system would mean revisiting the rules on > parameter susbstitution, unfortunately. I suspect however hard we try > to keep it the same there will be occasions where it doesn't fit. Parameter substitution is one of the parts which worry me because I don't understand it at all well. >From here on, I got very lost: > One other point: I became aware when writing the map that calls to the > system are inefficient. Even if you're assigning a parameter, there are the map? and what do you mean by "the system" - the current parameter system? Oliver -- This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-20 12:55 ` Oliver Kiddle @ 2002-03-20 13:53 ` Peter Stephenson 2002-03-20 17:41 ` Oliver Kiddle 2002-03-26 11:09 ` Oliver Kiddle 0 siblings, 2 replies; 11+ messages in thread From: Peter Stephenson @ 2002-03-20 13:53 UTC (permalink / raw) To: Zsh hackers list Oliver Kiddle wrote: > Does that approach sound reasonable? It sounds perfectly reasonable, the difficulty is probably how you make all the current stuff with getsparam etc. fit in with a table stored in the parameter. > > One other point: I became aware when writing the map that calls to the > > system are inefficient. Even if you're assigning a parameter, there are > > the map? > and what do you mean by "the system" - the current parameter system? This got truncated somehow, I meant the zsh/mapfile module, where $mapfile actually reads in a complete file of arbitrary length, and `mapfile[...]=' or `vared mapfile[...]' writes a value to it. The way the assignment code works, you have to retrieve the value first (in the case of vared, even if you just finished reading and modifying the value). This shouldn't be necessary and it's particularly inefficient in this case. This is where intelligent caching could help, at least in the case where you actually had to read in the file; if you mapped it, you would have to maintain extra system state information in order to unmap it and it's probably not worth it. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Science Park, Milton Road, Cambridge, CB4 0WH, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-20 13:53 ` Peter Stephenson @ 2002-03-20 17:41 ` Oliver Kiddle 2002-03-26 11:09 ` Oliver Kiddle 1 sibling, 0 replies; 11+ messages in thread From: Oliver Kiddle @ 2002-03-20 17:41 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh hackers list On Wed, Mar 20, 2002 at 01:53:00PM +0000, Peter Stephenson wrote: > > It sounds perfectly reasonable, the difficulty is probably how you make > all the current stuff with getsparam etc. fit in with a table stored in > the parameter. Yes. I was going to try to leave things like getsparam initially so that I don't break the current stuff. > This got truncated somehow, I meant the zsh/mapfile module, where > $mapfile actually reads in a complete file of arbitrary length, and > `mapfile[...]=' or `vared mapfile[...]' writes a value to it. The way > the assignment code works, you have to retrieve the value first (in the > case of vared, even if you just finished reading and modifying the Ah, I understand now. I suppose the problem is that there is a lot of code which reads the value of a param by going straight to the u union (just grep for pm->u.str in the source to see). It would be better if all getting and setting values went through functions in param.c. Calling something like fetchvalue would return a pointer to a Param but not actually retrieve the value of the parameter. This could be defered until actually reading the value. So there will need to be functions which do things like return association keys or assign to an array range in the method table. We could even make the param struct an opaque type - passing Params out as void pointers so that only code in params.c can dig about inside it. I'm not sure it is worth the bother though. Would it be a good idea to allow arrays to be arrays of any type such as integers. Ksh arrays can be arrays of floats, scalars or integers but not arrays of arrays or namespaces. Oliver This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-20 13:53 ` Peter Stephenson 2002-03-20 17:41 ` Oliver Kiddle @ 2002-03-26 11:09 ` Oliver Kiddle 2002-03-26 16:55 ` Bart Schaefer 1 sibling, 1 reply; 11+ messages in thread From: Oliver Kiddle @ 2002-03-26 11:09 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh hackers list I've been looking at the whole parameter code thing. What is the second parameter to the unsetfn function? Do we need it? Should I be looking to remove the overloading of ct in the param struct? How essential was the arr cache in the value struct? I don't think it should be in the value struct but either a local in getarg() or internal to the hash variable implementation. Also, what is isarr in the value struct used for? I have a suspicion that it is being overloaded a lot? Should we allow attributes like uppercase and integer to apply across an array like in ksh (this is messier for hashes as each element has its own param)? On Wed, Mar 20, 2002 at 01:53:00PM +0000, Peter Stephenson wrote: > Oliver Kiddle wrote: > > Does that approach sound reasonable? > > It sounds perfectly reasonable, the difficulty is probably how you make > all the current stuff with getsparam etc. fit in with a table stored in > the parameter. What worries me more is that it is making it messier to implement all the noddy specials because they then have to worry about things like assigning to a string subrange. We basically have two interfaces to the parameter system to worry about: the places where we can add hooks for specials (currently the gets, sets and unsetfn functions) and the interface which the rest of zsh can use the manipulate parameters. The difficulty I am having at the moment is knowing how much funcionality to draw into the functions which the specials can override. What do we ideally need to do things like mapfile efficiently beyond get, set and unset? A comment in parameter.c says "the zsh core doesn't support creation of special hashes, yet". What functions would we need to provide to better support special hashes here? If we allow special hashes to effectively not be a hash table of struct params we could lose some of the advantages of hashes having been implemented with each element a struct param. It'd cause problems for namerefs to hash elements. So I'm unsure. Do we ever want to have control over the conversion of a parameter's type for the purposes of a special? The patch below shows an initial start where some of the thinking came from 15158. The intention was that the set functions in the paramfns struct would convert the type of the parameter and that the get functions would check the type of the parameter and convert the output. For this to work, the get and set functions will need to be passed start and end values (or value structs) to handle ranges. Is this adding anything useful for the purposes of writing specials or just making them messier? I'm not sure whether or not to restore the unions for the get and set functions. What about other functionality in typeset_single - might that need to be overridden for the purposes of a special, e.g. changing the output format of a float? Oliver Scroll down to zsh.h to see the significant part of this patch. Also note intgetfn(). Index: Src/builtin.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v retrieving revision 1.73 diff -u -r1.73 builtin.c --- Src/builtin.c 24 Mar 2002 07:56:42 -0000 1.73 +++ Src/builtin.c 26 Mar 2002 10:21:44 -0000 @@ -1699,14 +1699,14 @@ Param apm; char **x; if (PM_TYPE(pm->flags) == PM_ARRAY) { - x = (*pm->gets.afn)(pm); + x = (*pm->m->aget)(pm); uniqarray(x); if (pm->ename && x) arrfixenv(pm->ename, x); } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename && (apm = (Param) paramtab->getnode(paramtab, pm->ename))) { - x = (*apm->gets.afn)(apm); + x = (*apm->m->aget)(apm); uniqarray(x); if (x) arrfixenv(pm->nam, x); @@ -1871,8 +1871,7 @@ * to make sure we only ever use the colonarr functions * when u.data is correctly set. */ - pm->sets.cfn = colonarrsetfn; - pm->gets.cfn = colonarrgetfn; + pm->m = &colonarrparamfns; pm->u.data = &altpm->u.arr; } @@ -1896,20 +1895,20 @@ */ switch (PM_TYPE(pm->flags)) { case PM_SCALAR: - pm->sets.cfn(pm, ztrdup("")); + pm->m->cset(pm, ztrdup("")); break; case PM_INTEGER: - pm->sets.ifn(pm, 0); + pm->m->iset(pm, 0); break; case PM_EFLOAT: case PM_FFLOAT: - pm->sets.ffn(pm, 0.0); + pm->m->fset(pm, 0.0); break; case PM_ARRAY: - pm->sets.afn(pm, mkarray(NULL)); + pm->m->aset(pm, mkarray(NULL)); break; case PM_HASHED: - pm->sets.hfn(pm, newparamtable(17, pm->nam)); + pm->m->hset(pm, newparamtable(17, pm->nam)); break; } } @@ -2408,7 +2407,7 @@ } else if (ss) { if (PM_TYPE(pm->flags) == PM_HASHED) { HashTable tht = paramtab; - if ((paramtab = pm->gets.hfn(pm))) { + if ((paramtab = pm->m->hget(pm))) { *--sse = 0; unsetparam(ss+1); *sse = ']'; Index: Src/exec.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/exec.c,v retrieving revision 1.40 diff -u -r1.40 exec.c --- Src/exec.c 17 Dec 2001 17:17:38 -0000 1.40 +++ Src/exec.c 26 Mar 2002 10:21:44 -0000 @@ -2460,20 +2460,20 @@ tpm->flags = pm->flags; switch (PM_TYPE(pm->flags)) { case PM_SCALAR: - tpm->sets.cfn(tpm, pm->u.str); + tpm->m->cset(tpm, pm->u.str); break; case PM_INTEGER: - tpm->sets.ifn(tpm, pm->u.val); + tpm->m->iset(tpm, pm->u.val); break; case PM_EFLOAT: case PM_FFLOAT: - tpm->sets.ffn(tpm, pm->u.dval); + tpm->m->fset(tpm, pm->u.dval); break; case PM_ARRAY: - tpm->sets.afn(tpm, pm->u.arr); + tpm->m->aset(tpm, pm->u.arr); break; case PM_HASHED: - tpm->sets.hfn(tpm, pm->u.hash); + tpm->m->hset(tpm, pm->u.hash); break; } } else Index: Src/module.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/module.c,v retrieving revision 1.9 diff -u -r1.9 module.c --- Src/module.c 18 May 2001 15:23:09 -0000 1.9 +++ Src/module.c 26 Mar 2002 10:21:44 -0000 @@ -1887,9 +1887,7 @@ pm->level = 0; pm->u.data = d->var; - pm->sets.ifn = (void (*)(Param, zlong)) d->set; - pm->gets.ifn = (zlong (*)(Param)) d->get; - pm->unsetfn = (void (*)(Param, int)) d->unset; + pm->m = d->m; return 0; } Index: Src/params.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/params.c,v retrieving revision 1.63 diff -u -r1.63 params.c --- Src/params.c 24 Mar 2002 23:52:49 -0000 1.63 +++ Src/params.c 26 Mar 2002 10:21:45 -0000 @@ -107,6 +107,108 @@ /**/ mod_export int termflags; +/* Method tables for parameters */ + +/**/ +struct paramfns colonarrparamfns = { + colonarrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + colonarrgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +/**/ +mod_export struct paramfns roparamfns = { + nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +struct paramfns stdparamfns = { + strsetfn, intsetfn, floatsetfn, arrsetfn, hashsetfn, + strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +static struct paramfns intvarparamfns = { + nullstrsetfn, intvarsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +static struct paramfns rointvarparamfns = { + nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +static struct paramfns strvarparamfns = { + strvarsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + strvargetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +static struct paramfns arrvarparamfns = { + nullstrsetfn, nullintsetfn, nullfloatsetfn, arrvarsetfn, nullhashsetfn, + strgetfn, intgetfn, floatgetfn, arrvargetfn, hashgetfn, + stdunsetfn +}; + +/**/ +mod_export struct paramfns hashvarparamfns = { + nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, hashsetfn, + strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + +static struct paramfns zlevarparamfns = { + nullstrsetfn, zlevarsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, + strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn, + stdunsetfn +}; + + +static struct paramfns pipestatparamfns = { + nullstrsetfn, nullintsetfn, nullfloatsetfn, pipestatsetfn, nullhashsetfn, + strgetfn, intgetfn, floatgetfn, pipestatgetfn, hashgetfn, + stdunsetfn +}; + +#define PFDEF1(A,B,C) static struct paramfns A = { \ + nullstrsetfn, B, nullfloatsetfn, nullarrsetfn, nullhashsetfn, \ + strgetfn, C, floatgetfn, arrgetfn, hashgetfn, \ + stdunsetfn \ +}; +PFDEF1(poundparamfns, nullintsetfn, poundgetfn) +PFDEF1(errnoparamfns, nullintsetfn, errnogetfn) +PFDEF1(gidparamfns, gidsetfn, gidgetfn) +PFDEF1(egidparamfns, egidsetfn, egidgetfn) +PFDEF1(histsizeparamfns, histsizesetfn, histsizegetfn) +PFDEF1(randomparamfns, randomsetfn, randomgetfn) +PFDEF1(savehistparamfns, savehistsizesetfn, savehistsizegetfn) +PFDEF1(secondsparamfns, secondssetfn, secondsgetfn) +PFDEF1(uidparamfns, uidsetfn, uidgetfn) +PFDEF1(euidparamfns, euidsetfn, euidgetfn) +PFDEF1(ttyidleparamfns, nullintsetfn, ttyidlegetfn) + +#define PFDEF2(A,B,C) static struct paramfns A = { \ + B, intsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, \ + C, intgetfn, floatgetfn, arrgetfn, hashgetfn, \ + stdunsetfn \ +}; +PFDEF2(usernameparamfns, usernamesetfn, usernamegetfn) +PFDEF2(dashparamfns, nullstrsetfn, dashgetfn) +PFDEF2(histcharsparamfns, histcharssetfn, histcharsgetfn) +PFDEF2(homeparamfns, homesetfn, homegetfn) +PFDEF2(termparamfns, termsetfn, termgetfn) +PFDEF2(wordcharsparamfns, wordcharssetfn, wordcharsgetfn) +PFDEF2(ifsparamfns, ifssetfn, ifsgetfn) +PFDEF2(underscoreparamfns, nullstrsetfn, underscoregetfn) +#ifdef USE_LOCALE +PFDEF2(langparamfns, langsetfn, strgetfn) +PFDEF2(lc_allparamfns, lc_allsetfn, strgetfn) +PFDEF2(lcparamfns, lcsetfn, strgetfn) +#endif + /* Nodes for special parameters for parameter hash table */ #ifdef HAVE_UNION_INIT @@ -118,10 +220,8 @@ struct hashnode *next; char *nam; /* hash data */ int flags; /* PM_* flags (defined in zsh.h) */ + struct paramfns *m; /* method table */ void *value; - void (*func1) _((void)); /* set func */ - char *(*func2) _((void)); /* get func */ - void (*unsetfn) _((Param, int)); /* unset func */ int ct; /* output base or field width */ char *env; /* location in environment, if exported */ char *ename; /* name of corresponding environment var */ @@ -133,33 +233,33 @@ static initparam special_params[] ={ #define SFN(X) BR(((void (*)_((Param, char *)))(X))) #define GFN(X) BR(((char *(*)_((Param)))(X))) -#define IPDEF1(A,B,C,D) {NULL,A,PM_INTEGER|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0} -IPDEF1("#", poundgetfn, nullintsetfn, PM_READONLY), -IPDEF1("ERRNO", errnogetfn, nullintsetfn, PM_READONLY), -IPDEF1("GID", gidgetfn, gidsetfn, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED), -IPDEF1("RANDOM", randomgetfn, randomsetfn, 0), -IPDEF1("SAVEHIST", savehistsizegetfn, savehistsizesetfn, PM_RESTRICTED), -IPDEF1("SECONDS", secondsgetfn, secondssetfn, 0), -IPDEF1("UID", uidgetfn, uidsetfn, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("EUID", euidgetfn, euidsetfn, PM_DONTIMPORT | PM_RESTRICTED), -IPDEF1("TTYIDLE", ttyidlegetfn, nullintsetfn, PM_READONLY), - -#define IPDEF2(A,B,C,D) {NULL,A,PM_SCALAR|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,0,NULL,NULL,NULL,0} -IPDEF2("USERNAME", usernamegetfn, usernamesetfn, PM_DONTIMPORT|PM_RESTRICTED), -IPDEF2("-", dashgetfn, nullstrsetfn, PM_READONLY), -IPDEF2("histchars", histcharsgetfn, histcharssetfn, PM_DONTIMPORT), -IPDEF2("HOME", homegetfn, homesetfn, 0), -IPDEF2("TERM", termgetfn, termsetfn, 0), -IPDEF2("WORDCHARS", wordcharsgetfn, wordcharssetfn, 0), -IPDEF2("IFS", ifsgetfn, ifssetfn, PM_DONTIMPORT), -IPDEF2("_", underscoregetfn, nullstrsetfn, PM_READONLY), +#define IPDEF1(A,D,E) {NULL,A,PM_INTEGER|PM_SPECIAL|D,&E,BR(NULL),10,NULL,NULL,NULL,0} +IPDEF1("#", PM_READONLY, poundparamfns), +IPDEF1("ERRNO", PM_READONLY, errnoparamfns), +IPDEF1("GID", PM_DONTIMPORT | PM_RESTRICTED, gidparamfns), +IPDEF1("EGID", PM_DONTIMPORT | PM_RESTRICTED, egidparamfns), +IPDEF1("HISTSIZE", PM_RESTRICTED, histsizeparamfns), +IPDEF1("RANDOM", 0, randomparamfns), +IPDEF1("SAVEHIST", PM_RESTRICTED, savehistparamfns), +IPDEF1("SECONDS", 0, secondsparamfns), +IPDEF1("UID", PM_DONTIMPORT | PM_RESTRICTED, uidparamfns), +IPDEF1("EUID", PM_DONTIMPORT | PM_RESTRICTED, euidparamfns), +IPDEF1("TTYIDLE", PM_READONLY, ttyidleparamfns), + +#define IPDEF2(A,D,E) {NULL,A,PM_SCALAR|PM_SPECIAL|D,&E,BR(NULL),0,NULL,NULL,NULL,0} +IPDEF2("USERNAME", PM_DONTIMPORT|PM_RESTRICTED, usernameparamfns), +IPDEF2("-", PM_READONLY, dashparamfns), +IPDEF2("histchars", PM_DONTIMPORT, histcharsparamfns), +IPDEF2("HOME", 0, homeparamfns), +IPDEF2("TERM", 0, termparamfns), +IPDEF2("WORDCHARS", 0, wordcharsparamfns), +IPDEF2("IFS", PM_DONTIMPORT, ifsparamfns), +IPDEF2("_", PM_READONLY, underscoreparamfns), #ifdef USE_LOCALE -# define LCIPDEF(name) IPDEF2(name, strgetfn, lcsetfn, PM_UNSET) -IPDEF2("LANG", strgetfn, langsetfn, PM_UNSET), -IPDEF2("LC_ALL", strgetfn, lc_allsetfn, PM_UNSET), +# define LCIPDEF(name) IPDEF2(name, PM_UNSET, lcparamfns) +IPDEF2("LANG", PM_UNSET, langparamfns), +IPDEF2("LC_ALL", PM_UNSET, lc_allparamfns), # ifdef LC_COLLATE LCIPDEF("LC_COLLATE"), # endif @@ -177,20 +277,20 @@ # endif #endif /* USE_LOCALE */ -#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),SFN(nullintsetfn),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0} +#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,&rointvarparamfns,BR((void *)B),10,NULL,NULL,NULL,0} IPDEF4("!", &lastpid), IPDEF4("$", &mypid), IPDEF4("?", &lastval), IPDEF4("LINENO", &lineno), IPDEF4("PPID", &ppid), -#define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),SFN(F),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0} -IPDEF5("COLUMNS", &columns, zlevarsetfn), -IPDEF5("LINES", &lines, zlevarsetfn), -IPDEF5("OPTIND", &zoptind, intvarsetfn), -IPDEF5("SHLVL", &shlvl, intvarsetfn), +#define IPDEF5(A,B,C) {NULL,A,PM_INTEGER|PM_SPECIAL,&C,BR((void *)B),10,NULL,NULL,NULL,0} +IPDEF5("COLUMNS", &columns, zlevarparamfns), +IPDEF5("LINES", &lines, zlevarparamfns), +IPDEF5("OPTIND", &zoptind, intvarparamfns), +IPDEF5("SHLVL", &shlvl, intvarparamfns), -#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(strvarsetfn),GFN(strvargetfn),stdunsetfn,0,NULL,NULL,NULL,0} +#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,&strvarparamfns,BR((void *)B),0,NULL,NULL,NULL,0} IPDEF7("OPTARG", &zoptarg), IPDEF7("NULLCMD", &nullcmd), IPDEF7("POSTEDIT", &postedit), @@ -206,7 +306,7 @@ IPDEF7("SPROMPT", &sprompt), IPDEF7("0", &argzero), -#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(colonarrsetfn),GFN(colonarrgetfn),stdunsetfn,0,NULL,C,NULL,0} +#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,&colonarrparamfns,BR((void *)B),0,NULL,C,NULL,0} IPDEF8("CDPATH", &cdpath, "cdpath", 0), IPDEF8("FIGNORE", &fignore, "fignore", 0), IPDEF8("FPATH", &fpath, "fpath", 0), @@ -218,17 +318,17 @@ /* MODULE_PATH is not imported for security reasons */ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), -#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),SFN(arrvarsetfn),GFN(arrvargetfn),stdunsetfn,0,NULL,C,NULL,0} +#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,&arrvarparamfns,BR((void *)B),0,NULL,C,NULL,0} #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), {NULL, NULL}, -#define IPDEF10(A,B,C) {NULL,A,PM_ARRAY|PM_SPECIAL,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0} +#define IPDEF10(A,B) {NULL,A,PM_ARRAY|PM_SPECIAL,&B,BR(NULL),10,NULL,NULL,NULL,0} -/* The following parameters are not avaible in sh/ksh compatibility * +/* The following parameters are not available in sh/ksh compatibility * * mode. All of these have sh compatible equivalents. */ -IPDEF1("ARGC", poundgetfn, nullintsetfn, PM_READONLY), -IPDEF2("HISTCHARS", histcharsgetfn, histcharssetfn, PM_DONTIMPORT), +IPDEF1("ARGC", PM_READONLY, poundparamfns), +IPDEF2("HISTCHARS", PM_DONTIMPORT, histcharsparamfns), IPDEF4("status", &lastval), IPDEF7("prompt", &prompt), IPDEF7("PROMPT", &prompt), @@ -248,7 +348,7 @@ IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), IPDEF9F("path", &path, "PATH", PM_RESTRICTED), -IPDEF10("pipestatus", pipestatgetfn, pipestatsetfn), +IPDEF10("pipestatus", pipestatparamfns), {NULL, NULL} }; @@ -448,9 +548,9 @@ if (v->arr) return v->arr; else if (PM_TYPE(v->pm->flags) == PM_ARRAY) - return v->arr = v->pm->gets.afn(v->pm); + return v->arr = v->pm->m->aget(v->pm); else if (PM_TYPE(v->pm->flags) == PM_HASHED) { - v->arr = paramvalarr(v->pm->gets.hfn(v->pm), v->isarr); + v->arr = paramvalarr(v->pm->m->hget(v->pm), v->isarr); /* Can't take numeric slices of associative arrays */ v->start = 0; v->end = numparamvals + 1; @@ -626,33 +726,7 @@ 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_EFLOAT: - case PM_FFLOAT: - pm->sets.ffn = floatsetfn; - pm->gets.ffn = floatgetfn; - 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; + pm->m = &stdparamfns; } /* Create a parameter, so that it can be assigned to. Returns NULL if the * @@ -737,7 +811,7 @@ * 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). + * with m->?set() usage). */ tpm->flags = pm->flags; tpm->ct = pm->ct; @@ -745,20 +819,20 @@ tpm->flags &= ~PM_SPECIAL; switch (PM_TYPE(pm->flags)) { case PM_SCALAR: - tpm->u.str = ztrdup(pm->gets.cfn(pm)); + tpm->u.str = ztrdup(pm->m->cget(pm)); break; case PM_INTEGER: - tpm->u.val = pm->gets.ifn(pm); + tpm->u.val = pm->m->iget(pm); break; case PM_EFLOAT: case PM_FFLOAT: - tpm->u.dval = pm->gets.ffn(pm); + tpm->u.dval = pm->m->fget(pm); break; case PM_ARRAY: - tpm->u.arr = zarrdup(pm->gets.afn(pm)); + tpm->u.arr = zarrdup(pm->m->aget(pm)); break; case PM_HASHED: - tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam); + tpm->u.hash = copyparamtable(pm->m->hget(pm), pm->nam); break; } /* @@ -984,10 +1058,10 @@ remnulargs(s); /* This is probably always a no-op, but ... */ if (!rev) { if (ishash) { - HashTable ht = v->pm->gets.hfn(v->pm); + HashTable ht = v->pm->m->hget(v->pm); if (!ht) { ht = newparamtable(17, v->pm->nam); - v->pm->sets.hfn(v->pm, ht); + v->pm->m->hset(v->pm, ht); } untokenize(s); if (!(v->pm = (Param) ht->getnode(ht, s))) { @@ -1445,15 +1519,15 @@ } return s; case PM_INTEGER: - convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct); + convbase(buf, v->pm->m->iget(v->pm), v->pm->ct); s = dupstring(buf); break; case PM_EFLOAT: case PM_FFLOAT: - s = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct, v->pm->flags, NULL); + s = convfloat(v->pm->m->fget(v->pm), v->pm->ct, v->pm->flags, NULL); break; case PM_SCALAR: - s = v->pm->gets.cfn(v->pm); + s = v->pm->m->cget(v->pm); break; default: s = NULL; @@ -1524,9 +1598,9 @@ if (v->inv) return v->start; if (PM_TYPE(v->pm->flags) == PM_INTEGER) - return v->pm->gets.ifn(v->pm); + return v->pm->m->iget(v->pm); if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) - return (zlong)v->pm->gets.ffn(v->pm); + return (zlong)v->pm->m->fget(v->pm); return mathevali(getstrvalue(v)); } @@ -1542,10 +1616,10 @@ } else if (v->inv) { mn.u.l = v->start; } else if (PM_TYPE(v->pm->flags) == PM_INTEGER) { - mn.u.l = v->pm->gets.ifn(v->pm); + mn.u.l = v->pm->m->iget(v->pm); } else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) { mn.type = MN_FLOAT; - mn.u.d = v->pm->gets.ffn(v->pm); + mn.u.d = v->pm->m->fget(v->pm); } else return matheval(getstrvalue(v)); return mn; @@ -1570,12 +1644,12 @@ #endif return; } else if (PM_TYPE(pm->flags) == PM_INTEGER) - convbase(val = buf, pm->gets.ifn(pm), pm->ct); + convbase(val = buf, pm->m->iget(pm), pm->ct); else if (pm->flags & (PM_EFLOAT|PM_FFLOAT)) - val = convfloat(pm->gets.ffn(pm), pm->ct, + val = convfloat(pm->m->iget(pm), pm->ct, pm->flags, NULL); else - val = pm->gets.cfn(pm); + val = pm->m->cget(pm); pm->flags |= PM_EXPORTED; pm->env = addenv(pm->nam, val, pm->flags); @@ -1603,14 +1677,14 @@ switch (PM_TYPE(v->pm->flags)) { case PM_SCALAR: if (v->start == 0 && v->end == -1) { - (v->pm->sets.cfn) (v->pm, val); + (v->pm->m->cset) (v->pm, val); if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct) v->pm->ct = strlen(val); } else { char *z, *x; int zlen; - z = dupstring((v->pm->gets.cfn) (v->pm)); + z = dupstring((v->pm->m->cget) (v->pm)); zlen = strlen(z); if (v->inv && unset(KSHARRAYS)) v->start--, v->end--; @@ -1629,13 +1703,13 @@ strncpy(x, z, v->start); strcpy(x + v->start, val); strcat(x + v->start, z + v->end); - (v->pm->sets.cfn) (v->pm, x); + (v->pm->m->cset) (v->pm, x); zsfree(val); } break; case PM_INTEGER: if (val) { - (v->pm->sets.ifn) (v->pm, mathevali(val)); + (v->pm->m->iset) (v->pm, mathevali(val)); zsfree(val); } if (!v->pm->ct && lastbase != -1) @@ -1645,7 +1719,7 @@ case PM_FFLOAT: if (val) { mnumber mn = matheval(val); - (v->pm->sets.ffn) (v->pm, (mn.type & MN_FLOAT) ? mn.u.d : + (v->pm->m->fset) (v->pm, (mn.type & MN_FLOAT) ? mn.u.d : (double)mn.u.l); zsfree(val); } @@ -1693,13 +1767,13 @@ setstrvalue(v, ztrdup(p)); break; case PM_INTEGER: - (v->pm->sets.ifn) (v->pm, (val.type & MN_INTEGER) ? val.u.l : + (v->pm->m->iset) (v->pm, (val.type & MN_INTEGER) ? val.u.l : (zlong) val.u.d); setstrvalue(v, NULL); break; case PM_EFLOAT: case PM_FFLOAT: - (v->pm->sets.ffn) (v->pm, (val.type & MN_INTEGER) ? + (v->pm->m->fset) (v->pm, (val.type & MN_INTEGER) ? (double)val.u.l : val.u.d); setstrvalue(v, NULL); break; @@ -1730,7 +1804,7 @@ if (PM_TYPE(v->pm->flags) == PM_HASHED) arrhashsetfn(v->pm, val, 0); else - (v->pm->sets.afn) (v->pm, val); + (v->pm->m->aset) (v->pm, val); } else if (v->start == -1 && v->end == 0 && PM_TYPE(v->pm->flags) == PM_HASHED) { arrhashsetfn(v->pm, val, 1); @@ -1751,7 +1825,7 @@ } if (v->end < v->start) v->end = v->start; - q = old = v->pm->gets.afn(v->pm); + q = old = v->pm->m->aget(v->pm); n = arrlen(old); if (v->start < 0) { v->start += n; @@ -1779,7 +1853,7 @@ *p++ = ztrdup(*q++); *p = NULL; - (v->pm->sets.afn) (v->pm, new); + (v->pm->m->aset) (v->pm, new); freearray(val); } } @@ -1841,7 +1915,7 @@ if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) && PM_TYPE(v->pm->flags) == PM_ARRAY) - return v->pm->gets.afn(v->pm); + return v->pm->m->aget(v->pm); return NULL; } @@ -1856,7 +1930,7 @@ if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) && PM_TYPE(v->pm->flags) == PM_HASHED) - return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTVALS); + return paramvalarr(v->pm->m->hget(v->pm), SCANPM_WANTVALS); return NULL; } @@ -1871,7 +1945,7 @@ if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) && PM_TYPE(v->pm->flags) == PM_HASHED) - return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTKEYS); + return paramvalarr(v->pm->m->hget(v->pm), SCANPM_WANTKEYS); return NULL; } @@ -1945,7 +2019,7 @@ return v->pm; /* avoid later setstrvalue() call */ case PM_ARRAY: if (unset(KSHARRAYS)) { - v->start = arrlen(v->pm->gets.afn(v->pm)); + v->start = arrlen(v->pm->m->aget(v->pm)); v->end = v->start + 1; } else { /* ksh appends scalar to first element */ @@ -1960,7 +2034,7 @@ if (v->end > 0) v->start = v->end; else - v->start = v->end = strlen(v->pm->gets.cfn(v->pm)) + + v->start = v->end = strlen(v->pm->m->cget(v->pm)) + v->end + 1; break; case PM_INTEGER: @@ -2057,7 +2131,7 @@ if (augment) { if (v->start == 0 && v->end == -1) { if (PM_TYPE(v->pm->flags) & PM_ARRAY) { - v->start = arrlen(v->pm->gets.afn(v->pm)); + v->start = arrlen(v->pm->m->aget(v->pm)); v->end = v->start + 1; } else if (PM_TYPE(v->pm->flags) & PM_HASHED) v->start = -1, v->end = 0; @@ -2065,7 +2139,7 @@ if (v->end > 0) v->start = v->end--; else if (PM_TYPE(v->pm->flags) & PM_ARRAY) { - v->end = arrlen(v->pm->gets.afn(v->pm)) + v->end; + v->end = arrlen(v->pm->m->aget(v->pm)) + v->end; v->start = v->end + 1; } } @@ -2225,7 +2299,7 @@ zerr("%s: restricted", pm->nam, 0); return; } - pm->unsetfn(pm, exp); + pm->m->unsetfn(pm, exp); if ((pm->flags & PM_EXPORTED) && pm->env) { delenv(pm->env); pm->env = NULL; @@ -2263,7 +2337,7 @@ if ((PM_TYPE(oldpm->flags) == PM_SCALAR) && !(pm->flags & PM_HASHELEM) && (oldpm->flags & PM_NAMEDDIR) && - oldpm->sets.cfn == strsetfn) + oldpm->m->cset == strsetfn) adduserdir(oldpm->nam, oldpm->u.str, 0, 0); if (oldpm->flags & PM_EXPORTED) { /* @@ -2287,9 +2361,9 @@ 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; + case PM_SCALAR: pm->m->cset(pm, NULL); break; + case PM_ARRAY: pm->m->aset(pm, NULL); break; + case PM_HASHED: pm->m->hset(pm, NULL); break; default: if (!(pm->flags & PM_SPECIAL)) pm->u.str = NULL; @@ -2304,13 +2378,19 @@ mod_export zlong intgetfn(Param pm) { - return pm->u.val; + if (!pm) + return 0; + if (PM_TYPE(pm->flags) == PM_INTEGER) + return pm->u.val; + if (pm->flags & (PM_EFLOAT|PM_FFLOAT)) + return (zlong)pm->m->fget(pm); + return mathevali(pm->m->cget(pm)); } /* Function to set value of an integer parameter */ /**/ -static void +mod_export void intsetfn(Param pm, zlong x) { pm->u.val = x; @@ -2319,7 +2399,7 @@ /* Function to get value of a floating point parameter */ /**/ -static double +mod_export double floatgetfn(Param pm) { return pm->u.dval; @@ -2413,7 +2493,7 @@ { /* 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. */ + * it's up to pm->m->hset() what to do. */ int alen = arrlen(val); HashTable opmtab = paramtab, ht = 0; char **aptr = val; @@ -2427,7 +2507,7 @@ return; } if (alen) - if (!(augment && (ht = paramtab = pm->gets.hfn(pm)))) + if (!(augment && (ht = paramtab = pm->m->hget(pm)))) ht = paramtab = newparamtable(17, pm->nam); while (*aptr) { /* The parameter name is ztrdup'd... */ @@ -2443,14 +2523,13 @@ setstrvalue(v, *aptr++); } paramtab = opmtab; - pm->sets.hfn(pm, ht); + pm->m->hset(pm, ht); free(val); /* not freearray() */ } /* * These functions are used as the set function for special parameters that - * cannot be set by the user. The set is incomplete as the only such - * parameters are scalar and integer. + * cannot be set by the user. */ /**/ @@ -2465,6 +2544,20 @@ nullintsetfn(Param pm, zlong x) {} +/**/ +void +nullfloatsetfn(Param pm, double x) +{} + +/**/ +void +nullarrsetfn(Param pm, char **x) +{} + +/**/ +void +nullhashsetfn(Param pm, HashTable x) +{} /* Function to get value of generic special integer * * parameter. data is pointer to global variable * @@ -2717,10 +2810,10 @@ /**/ void -uidsetfn(Param pm, uid_t x) +uidsetfn(Param pm, zlong x) { #ifdef HAVE_SETUID - setuid(x); + setuid((uid_t)x); #endif } @@ -2737,10 +2830,10 @@ /**/ void -euidsetfn(Param pm, uid_t x) +euidsetfn(Param pm, zlong x) { #ifdef HAVE_SETEUID - seteuid(x); + seteuid((uid_t)x); #endif } @@ -2757,10 +2850,10 @@ /**/ void -gidsetfn(Param pm, gid_t x) +gidsetfn(Param pm, zlong x) { #ifdef HAVE_SETUID - setgid(x); + setgid((gid_t)x); #endif } @@ -2777,10 +2870,10 @@ /**/ void -egidsetfn(Param pm, gid_t x) +egidsetfn(Param pm, zlong x) { #ifdef HAVE_SETEUID - setegid(x); + setegid((gid_t)x); #endif } @@ -3437,20 +3530,20 @@ if (!(tpm->flags & PM_NORESTORE)) switch (PM_TYPE(pm->flags)) { case PM_SCALAR: - pm->sets.cfn(pm, tpm->u.str); + pm->m->cset(pm, tpm->u.str); break; case PM_INTEGER: - pm->sets.ifn(pm, tpm->u.val); + pm->m->iset(pm, tpm->u.val); break; case PM_EFLOAT: case PM_FFLOAT: - pm->sets.ffn(pm, tpm->u.dval); + pm->m->fset(pm, tpm->u.dval); break; case PM_ARRAY: - pm->sets.afn(pm, tpm->u.arr); + pm->m->aset(pm, tpm->u.arr); break; case PM_HASHED: - pm->sets.hfn(pm, tpm->u.hash); + pm->m->hset(pm, tpm->u.hash); break; } zfree(tpm, sizeof(*tpm)); @@ -3476,7 +3569,7 @@ /* Since the second flag to unsetfn isn't used, I don't * * know what its value should be. */ if (delunset) - pm->unsetfn(pm, 1); + pm->m->unsetfn(pm, 1); zsfree(pm->nam); /* If this variable was tied by the user, ename was ztrdup'd */ if (pm->flags & PM_TIED) @@ -3551,27 +3644,27 @@ switch (PM_TYPE(p->flags)) { case PM_SCALAR: /* string: simple output */ - if (p->gets.cfn && (t = p->gets.cfn(p))) + if (p->m->cget && (t = p->m->cget(p))) quotedzputs(t, stdout); break; case PM_INTEGER: /* integer */ #ifdef ZSH_64_BIT_TYPE - fputs(output64(p->gets.ifn(p)), stdout); + fputs(output64(p->m->iget(p)), stdout); #else - printf("%ld", p->gets.ifn(p)); + printf("%ld", p->m->iget(p)); #endif break; case PM_EFLOAT: case PM_FFLOAT: /* float */ - convfloat(p->gets.ffn(p), p->ct, p->flags, stdout); + convfloat(p->m->fget(p), p->ct, p->flags, stdout); break; case PM_ARRAY: /* array */ if (!(printflags & PRINT_KV_PAIR)) putchar('('); - u = p->gets.afn(p); + u = p->m->aget(p); if(*u) { quotedzputs(*u++, stdout); while (*u) { @@ -3587,7 +3680,7 @@ if (!(printflags & PRINT_KV_PAIR)) putchar('('); { - HashTable ht = p->gets.hfn(p); + HashTable ht = p->m->hget(p); if (ht) scanhashtable(ht, 0, 0, PM_UNSET, ht->printnode, PRINT_KV_PAIR); Index: Src/subst.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/subst.c,v retrieving revision 1.30 diff -u -r1.30 subst.c --- Src/subst.c 22 Feb 2002 17:28:06 -0000 1.30 +++ Src/subst.c 26 Mar 2002 10:21:45 -0000 @@ -1261,7 +1261,7 @@ aval = getarrvalue(v); } else { if (v->pm->flags & PM_ARRAY) { - int tmplen = arrlen(v->pm->gets.afn(v->pm)); + int tmplen = arrlen(v->pm->m->aget(v->pm)); if (v->start < 0) v->start += tmplen + v->inv; @@ -1539,7 +1539,7 @@ if (arrasg > 1) { Param pm = sethparam(idbeg, a); if (pm) - aval = paramvalarr(pm->gets.hfn(pm), hkeys|hvals); + aval = paramvalarr(pm->m->hget(pm), hkeys|hvals); } else setaparam(idbeg, a); } else { Index: Src/zsh.h =================================================================== RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v retrieving revision 1.36 diff -u -r1.36 zsh.h --- Src/zsh.h 17 Dec 2001 17:17:38 -0000 1.36 +++ Src/zsh.h 26 Mar 2002 10:21:45 -0000 @@ -294,6 +294,7 @@ typedef struct alias *Alias; typedef struct param *Param; typedef struct paramdef *Paramdef; +typedef struct paramfns *ParamFns; typedef struct cmdnam *Cmdnam; typedef struct shfunc *Shfunc; typedef struct funcstack *Funcstack; @@ -1051,6 +1052,7 @@ HashNode next; /* next in hash chain */ char *nam; /* hash data */ int flags; /* PM_* flags */ + ParamFns m; /* method table */ /* the value of this parameter */ union { @@ -1063,27 +1065,6 @@ HashTable hash; /* value if declared assoc (PM_HASHED) */ } u; - /* pointer to function to set value of this parameter */ - union { - void (*cfn) _((Param, char *)); - void (*ifn) _((Param, zlong)); - void (*ffn) _((Param, double)); - void (*afn) _((Param, char **)); - void (*hfn) _((Param, HashTable)); - } sets; - - /* pointer to function to get value of this parameter */ - union { - char *(*cfn) _((Param)); - zlong (*ifn) _((Param)); - double (*ffn) _((Param)); - char **(*afn) _((Param)); - HashTable (*hfn) _((Param)); - } gets; - - /* pointer to function to unset this parameter */ - void (*unsetfn) _((Param, int)); - int ct; /* output base or field width */ char *env; /* location in environment, if exported */ char *ename; /* name of corresponding environment var */ @@ -1091,6 +1072,27 @@ int level; /* if (old != NULL), level of localness */ }; + +/* method table for parameters */ +struct paramfns { + /* pointer to functions to set value of this parameter */ + void (*cset) _((Param, char *)); + void (*iset) _((Param, zlong)); + void (*fset) _((Param, double)); + void (*aset) _((Param, char **)); + void (*hset) _((Param, HashTable)); + + /* pointer to function to get value of this parameter */ + char *(*cget) _((Param)); + zlong (*iget) _((Param)); + double (*fget) _((Param)); + char **(*aget) _((Param)); + HashTable (*hget) _((Param)); + + /* pointer to function to unset this parameter */ + void (*unsetfn) _((Param, int)); +}; + /* flags for parameters */ /* parameter types */ @@ -1184,9 +1186,7 @@ char *name; int flags; void *var; - void *set; - void *get; - void *unset; + ParamFns m; }; #define PARAMDEF(name, flags, var, set, get, unset) \ This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-26 11:09 ` Oliver Kiddle @ 2002-03-26 16:55 ` Bart Schaefer 0 siblings, 0 replies; 11+ messages in thread From: Bart Schaefer @ 2002-03-26 16:55 UTC (permalink / raw) To: Oliver Kiddle; +Cc: Zsh hackers list On Mar 26, 11:09am, Oliver Kiddle wrote: } } What is the second parameter to the unsetfn function? Do we need it? It's telling the unset function whether the parameter is being unset at the end of a local parameter scope (value 0), or either globally or by explicit `unset' command (1). I don't know if anything actually uses it, and there's at least one place where it may not be getting propagated correctly. } Should I be looking to remove the overloading of ct in the param } struct? It wouldn't hurt. } How essential was the arr cache in the value struct? I don't think } it should be in the value struct but either a local in getarg() or } internal to the hash variable implementation. It's used in several places via getvaluearr(), so at this point it is relied on by ordinary arrays as well; it's merely not as expensive to recompute an ordinary array (unless maybe it's a special of some kind). If your patch is going to do away with getvaluearr(), Value.arr can go as well. } Also, what is isarr in the value struct used for? I have a suspicion } that it is being overloaded a lot? At its basest level, it tells the parameter substitution code whether the parameter whose value was fetched may be treated as an array. It has in fact been overloaded to pass flags to the associative array scanning code to tell whether keys or values should be returned and whether to return all matching items or just the first one found. } Should we allow attributes like uppercase and integer to apply across } an array like in ksh (this is messier for hashes as each element has } its own param)? I don't know what the ksh implementation of this is like -- does it apply the conversion at fetch time, or at assign time? Zsh has the added complication of being able to fetch the keys of an assoc -- those attributes should not apply in that case. } What worries me more is that it is making it messier to implement } all the noddy specials because they then have to worry about things } like assigning to a string subrange. } } We basically have two interfaces to the parameter system to worry } about: the places where we can add hooks for specials (currently the } gets, sets and unsetfn functions) and the interface which the rest of } zsh can use the manipulate parameters. Right, and I think these should remain separate. The problem so far has been that other code would use whichever level was the fastest or simplest, rather than respecting what should have been API boundaries. The way I would structure this is: The lowest-level API provides functions to set and get scalars (strings, ints, etc.), arrays, array elements, and associative array elements (including getting the keys or values). An intermediate API provides functions implemented in terms of the above to set and get string ranges, array slices, and arrays of associative array elements. Special parameters have the option of implementing only the lowest-level API and using the functions from the intermediate one, or of providing the intermediate ones for efficiency or other effects. The highest level API, used by the rest of zsh, provides all this and everything else (such as mapping some attributes across array values at fetch time, if that's appropriate), implemented by calling the two lower level APIs. The complication arises when we add in nested substitutions, where the result of an inner substitution has to be treated as a parameter value for purposes of outer substitutions. I suggest we actually create a dummy parameter in this case rather than trying to handle everything via manipulation of the Value structure -- but that means some pretty heavy rewriting of paramsubst() and getarg(). If we did create a dummy parameter, we could even give it a name and let the surrounding substitutions refer to it explicitly, e.g.: ... ${$(some command):+blah blah $_ blah blah} ... could be the same as tmp=$(some command) ... ${tmp:+blah blah $tmp blah blah} ... } A comment in parameter.c says "the zsh core doesn't support creation of } special hashes, yet". What functions would we need to provide to better } support special hashes here? I think we can defer this until we have the rest of the mess straightened out. } Do we ever want to have control over the conversion of a parameter's } type for the purposes of a special? [...] } } What about other functionality in typeset_single - might that need to } be overridden for the purposes of a special, e.g. changing the output } format of a float? I haven't looked at your patch in detail yet, but these seems like things that could go in the optional intermediate-level API. -- Bart Schaefer Brass Lantern Enterprises http://www.well.com/user/barts http://www.brasslantern.com Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: special/readonly variables in sh emulation 2002-03-18 15:41 ` Oliver Kiddle 2002-03-19 1:43 ` Bart Schaefer @ 2002-03-19 11:27 ` Peter Stephenson 1 sibling, 0 replies; 11+ messages in thread From: Peter Stephenson @ 2002-03-19 11:27 UTC (permalink / raw) To: Zsh hackers list Oliver Kiddle wrote: > So to start this off, if we start by getting together a list of: > 1. what we think is wrong with the current implementation > 2. what it has got right and should be preserved, > 3. what new features we might want to support > 4. any ideas for the implementation, in particular on the data > structure and the interface. > 5. anything else What's wrong is that it's all very messy; there is a dense hierarchy of functions in params.c, plus code to handle typeset in builtin.c which interacts in a non-trivial way with the core code, plus extra code to handle function scoping, plus quite a lot of duplication of parameter functionality elsewhere when we need to do something special with functions, in particular in the special parameter modules. What we need is a small number of uniformly defined entry points to the parameter system which hide the workings of the structure. That way we can implement particular special parameters any way we like, and can easily trap all entry points for special handling of discipline functions. Ideally --- I don't know if this is feasible --- the parameter type as well as the representation should be irrelevant to code outside the parameter system. It should be possible to change an existing parameter's type by an assignment, or create a new one at a new scoping level, by supplying flags to indicate that is allowed or wanted, but the actual decision about whether to do that should be inside the parameter system. This puts the horrible logic in typeset_single() where it should be. Unfortunately there are dozens of different things you can do with parameters: When assigning - create a new parameter - overriding an existing one - maybe taking account of whether or not it's special - hiding an existing one in a higher function scope - converting an old one - maybe inheriting some of its properties (for example, keeping the value but changing the floating point output format) - pass down an input which may be scalar, array, numeric (it depends on the type of parameter what it will do with each) - handle array slices - handle operations on array slices as given by subscript flags - handle quoting, e.g. what a scalar does with an array slice may depend on whether it is in quotes When retrieving ... same sort of thing ... Much of this is currently done by ad hoc code in places like typeset_single() and paramsubst() which looks at the parameter type and alters the value accodingly before passing it down for assignment. It may be we can't get around all this, and as the type is likely to remain exposed maybe we can continue to handle it but still keep a neater interface to the core parameter code. Maybe we can help things along by introducing contexts. The arguments of an array assignment or substitution with explicit word-splitting would retrieve a parameter in an array context, although the parameter could be a scalar, or an integer. (We would need extra flags for types of associative array substitution, subscripts --- also required in scalar contexts --- etc.) This would always return an array, but that might be a single word. Similarly, a numeric context would always return an mnumber, and the parameter code itself would be responsible for converting the parameter to an mnumber. This is already roughly what happens, but the interface isn't by any stretch of the imagination simple or uniform --- sometimes we call the parameters `gets.?fn' directly, sometimes we use get?param(), sometimes we have calls to getvalue() to generate intermediate values for tinkering with. As far as the `value' struct goes, I would suggest either we get rid of it, or we use it only inside the parameter system, or we always use it as part of the parameter interface --- anyway, the current hybrid is rather a mess. Also, I don't know what to do about word-splitting. It might be neater to make that internal to the parameter system, passing information down into it. However, this may be unnecessary. Very likely any consistent system would mean revisiting the rules on parameter susbstitution, unfortunately. I suspect however hard we try to keep it the same there will be occasions where it doesn't fit. One other point: I became aware when writing the map that calls to the system are inefficient. Even if you're assigning a parameter, there are cases when you currently read the value. So maybe too naive a system of encapsulation (assuming there's always a real parameter value sitting there which you can access at any point) isn't the best way of doing it. Or maybe (I haven't looked in any detail) it's good enough to be more careful about separating the retrieval of information about the parameter from retrieval of its value. Here's one other idea: suppose we extend the heap system so that anyone using a heap can test whether the memory is still valid. Then we can have a transparent way of caching information for a short time inside the parameter code --- next time it looks for a value, it can tell if the cache is valid, and if it is, we are still in the same operation (because otherwise the heap would have been popped) and it can use whatever it cached. I'm not sure how efficiently we can implement the validity test, however: the first thing that comes to mind is having heaps `marked' with a single integer which is always incremented and which eventually simply wraps. But that's not good enough, since a heap is still valid when another one is pushed, so it would probably have to be a linked list of heap ids. Maybe this idea doesn't gain very much, but the hope is that you can do repeated operations on parameters in a simple fashion and rely on them being efficiently implemented underneath. I expect you're now as confused as I am. -- Peter Stephenson <pws@csr.com> Software Engineer CSR Ltd., Science Park, Milton Road, Cambridge, CB4 0WH, UK Tel: +44 (0)1223 392070 ********************************************************************** The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. ********************************************************************** ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2002-04-03 14:57 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-04-03 14:57 special/readonly variables in sh emulation Oliver Kiddle -- strict thread matches above, loose matches on Subject: below -- 2002-03-18 12:56 Oliver Kiddle 2002-03-18 14:07 ` Peter Stephenson 2002-03-18 15:41 ` Oliver Kiddle 2002-03-19 1:43 ` Bart Schaefer 2002-03-20 12:55 ` Oliver Kiddle 2002-03-20 13:53 ` Peter Stephenson 2002-03-20 17:41 ` Oliver Kiddle 2002-03-26 11:09 ` Oliver Kiddle 2002-03-26 16:55 ` Bart Schaefer 2002-03-19 11:27 ` Peter Stephenson
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).