zsh-workers
 help / color / mirror / code / Atom feed
* typeset -p output gives shows variables which can't be read back in
@ 2011-02-27 11:44 Rocky Bernstein
  2011-02-27 21:01 ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Rocky Bernstein @ 2011-02-27 11:44 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 2027 bytes --]

I would like to save to a file shell variables so that I can run a nested
zsh and then read these back in. It is becoming a bit of a challenge because
this in the output:

typeset -i10 -r !=0
typeset -i10 -r '#'=0
typeset -i10 -r '$'=15221
typeset -ar '*'
*=()
typeset -r -=569Xfy
typeset 0=_Dbg_do_shell
typeset -i10 -r '?'=0
typeset -ar @
@=()
typeset -rx _=-p

Failing a better solution, I think what I'll have to do is store IFS=''
typeset -p into an array and check each item of the array. But even this is
turning out to be a bit challenging.
One thing that one needs to do is look for read-only variables and then I
guess turn that into a test followed by the typeset. That is

typeset -p ARGC 2>/dev/null 1>/&2 && typeset -i10- r ARGC=0

Next one needs to check that the types valid which would weed out  the lines
above.

But then we come to the typeset -ar '*' line which I guess flows onto the
next line. At first I thought I could remove any lines that don't start with
"typeset", but this is wrong because I could have a line like:

typeset ZSH_DEBUG_CMD='if [ -d /etc/profile.d ]
then
for i in /etc/profile.d/*.sh
do
if [ -r $i ]
then
. $i
fi
done
unset i
fi'

and all of that will read back in fine.

Any suggestions?

A little bit of context of why I am doing this. Recently in the zsh debugger
I've added the ability to go into a nested zsh, and often one wants the
existing environment of the debugged program  preserved in this nested zsh.

Lastly, related on a different topic. I notice there's no option for
sourcing a startup file by name. Instead the closest thing is to create a
temporary directory and in that create a file called .zshenv and set
ZDOTDIR. This works, but strikes me as a bit awkward and more convoluted
than adding an option to indicated an additional profile to run.  Many
POSIX-like shell languages, notably ksh don't provide such an option, bash
does and it is called --init-file. And "higher-level" scripting languages
which have modules like Perl, Python, or Ruby all do as well.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-02-27 11:44 typeset -p output gives shows variables which can't be read back in Rocky Bernstein
@ 2011-02-27 21:01 ` Bart Schaefer
  2011-02-28  5:08   ` Rocky Bernstein
  0 siblings, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2011-02-27 21:01 UTC (permalink / raw)
  To: zsh-workers

On Feb 27,  6:44am, Rocky Bernstein wrote:
} 
} A little bit of context of why I am doing this. Recently in the zsh
} debugger I've added the ability to go into a nested zsh, and often one
} wants the existing environment of the debugged program preserved in
} this nested zsh.

You're kind of doomed here from the start.  If the debugger is inside
a shell function, for example, you're never going to get scoping back.
 
} I would like to save to a file shell variables so that I can run a
} nested zsh and then read these back in.  It is becoming a bit of a
} challenge because this in the output:
} 
} typeset -i10 -r !=0

Hm, I'm a bit surprised the '!' isn't quoted there; but the real issue
is that you get "not an identifier" or the like for a number of those,
and "can't change type" for ones that come from zsh/parameter, plus a
few "read-only variable" complaints.

} typeset -ar '*'

Hmm, strange.  That one does NOT give "not an identifier" ...

} *=()

... but that of course bombs with a globbing error.

} Failing a better solution, I think what I'll have to do is store IFS=''
} typeset -p into an array and check each item of the array.

The zsh/parameter module $parameters hash already tells you nearly all
you need to know.  Something like this:

    () {
      local param type
      for param type in "${(kv@)parameters}"
      do
        case "$type" in
        (*local*) continue;;   # Skip loop variables
        (*export*) continue;;  # No need to dump/restore if exported?
        (*special*) continue;; # Maintained by the shell
        (*readonly*) continue;;
        (*) typeset -p "$param";;
        esac
      done
    }

You can avoid zsh/parameter by parsing the output of "typeset +m +":

    () {
      local param type description
      typeset +m + | while read -A description
      do
        param="${description[-1]}"
        description[-1]=()
        if (( ${#description} ))
        then type="${description[*]}"
        else type=scalar
        fi
        case "$type" in
        (*local*) continue;;   # Skip loop variables
        (*export*) continue;;  # No need to dump/restore if exported?
        (*readonly*) continue;;
        (*) typeset -p "$param";;
        esac
      done
    }

However, that doesn't let you catch "special" parameters, though you
can still filter the readonly subset.

Note both of these techniques still miss things like:

    typeset -T foo FOO

I.e., there's no way to discover by examination that an array and scalar
have been tied together.

} But then we come to the typeset -ar '*' line which I guess flows onto the
} next line.

Not exactly "flows", but for arrays and associative arrays (hashes) the 
value can't be supplied in the typeset command, so an assignment line is
needed.

Also you may have to be careful with the order of assignments when you
read the file back in.  Some assignments to special variables (like to
the "options" hash) might change shell behavior in unexpected ways.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-02-27 21:01 ` Bart Schaefer
@ 2011-02-28  5:08   ` Rocky Bernstein
  2011-02-28  7:09     ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Rocky Bernstein @ 2011-02-28  5:08 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 6094 bytes --]

Thanks for the suggestions. I had been parsing typeset -p output by
splitting words and using a regexp match. Now, thanks to your suggestion, I
use the parameters module.

As for the typeset -T and typeset -p not showing -T associations, I think
that's a misfeature. What's shown now are array assignments and you don't
reliably know what goes with what. Much better would be to show the
association. That is if I run:
   typeset -T foo FOO
then typeset -T should echo that among the other -T possibilities. I can
always get the array and scalar values if I want. But getting the other
information, as you say, is not easy if possible at all.

Should I look into providing a patch for this?

Saving an environment for reloading into another session, whether nested or
not, might be useful in other contexts. Possibly the code you or I have in
zshdb could be turned into a function and put inside the parameter module?


On Sun, Feb 27, 2011 at 4:01 PM, Bart Schaefer <schaefer@brasslantern.com>wrote:

> On Feb 27,  6:44am, Rocky Bernstein wrote:
> }
> } A little bit of context of why I am doing this. Recently in the zsh
> } debugger I've added the ability to go into a nested zsh, and often one
> } wants the existing environment of the debugged program preserved in
> } this nested zsh.
>
> You're kind of doomed here from the start.  If the debugger is inside
> a shell function, for example, you're never going to get scoping back.
>

Not true in a couple of ways. First even if you changing values doesn't
persist, it is
useful to be able to see the values.

What I'm thinking of now is adding a function save_var which takes the name
of
a variable one wants to persist. In an at_exit hook (or whatever the
equivalent is on zsh),
then those variables are written out to a file similar to what was done on
entry to get all of those
variables set.

If there is something like a tie function like there is in Perl or a
discipline function on a varaible
like ksh, that might be used, but this would be on a per-variable basis.

Other comments are in line below.


>
> } I would like to save to a file shell variables so that I can run a
> } nested zsh and then read these back in.  It is becoming a bit of a
> } challenge because this in the output:
> }
> } typeset -i10 -r !=0
>
> Hm, I'm a bit surprised the '!' isn't quoted there; but the real issue
> is that you get "not an identifier" or the like for a number of those,
> and "can't change type" for ones that come from zsh/parameter, plus a
> few "read-only variable" complaints.
>
> } typeset -ar '*'
>
> Hmm, strange.  That one does NOT give "not an identifier" ...
>
> } *=()
>
> ... but that of course bombs with a globbing error.
>

So although I can see how this might be useful as an explanation, I think
it would be nice if there were some simple way (i.e. something in the
typeset -p command)
to filter out those things that can't be source'd back in.


>
> } Failing a better solution, I think what I'll have to do is store IFS=''
> } typeset -p into an array and check each item of the array.
>
> The zsh/parameter module $parameters hash already tells you nearly all
> you need to know.  Something like this:
>
>    () {
>      local param type
>      for param type in "${(kv@)parameters}"
>      do
>        case "$type" in
>        (*local*) continue;;   # Skip loop variables
>        (*export*) continue;;  # No need to dump/restore if exported?
>        (*special*) continue;; # Maintained by the shell
>        (*readonly*) continue;;
>        (*) typeset -p "$param";;
>        esac
>      done
>    }
>
> You can avoid zsh/parameter by parsing the output of "typeset +m +":
>
>    () {
>      local param type description
>      typeset +m + | while read -A description
>      do
>        param="${description[-1]}"
>        description[-1]=()
>        if (( ${#description} ))
>        then type="${description[*]}"
>        else type=scalar
>        fi
>        case "$type" in
>        (*local*) continue;;   # Skip loop variables
>        (*export*) continue;;  # No need to dump/restore if exported?
>        (*readonly*) continue;;
>        (*) typeset -p "$param";;
>        esac
>      done
>    }
>

Thanks again. I have modified the code to do something like this. Note
however I don't want to
skip local variables, because in a debugger that's one of the important
things we want to examine.

And read-only variables I want to  skip only if they are already set. That's
why I had that
typeset -p $var >/dev/null 2>&1 ||  prefix in the code before. (I had
erroneously used && instead of ||
and and a stray character in there.)

But all of this is easily fixed.


> However, that doesn't let you catch "special" parameters, though you
> can still filter the readonly subset.
>
> Note both of these techniques still miss things like:
>
>    typeset -T foo FOO
>
> I.e., there's no way to discover by examination that an array and scalar
> have been tied together.
>
> } But then we come to the typeset -ar '*' line which I guess flows onto the
> } next line.
>
> Not exactly "flows", but for arrays and associative arrays (hashes) the
> value can't be supplied in the typeset command, so an assignment line is
> needed.
>

Yes, I meant that the semantic description of the variable flows into the
next line, not that there was one
statement split on two lines.  I often write these two statements on one
like with a semicolon
in between.

But while we are being precise, let me point out that it is wrong to say
that a local variable is a
"loop" variable as you suggest in the code above.


> Also you may have to be careful with the order of assignments when you
> read the file back in.  Some assignments to special variables (like to
> the "options" hash) might change shell behavior in unexpected ways.
>

Ok. Thanks, I will keep that in mind. Right now, I'm skipping the special
variables as you had in your code.

Should I need them and I discover that there is an ordering problem, I think
it is a simple matter to put these
in a list which gets run in list order after doing other variables first

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-02-28  5:08   ` Rocky Bernstein
@ 2011-02-28  7:09     ` Bart Schaefer
  2011-03-01  3:09       ` Rocky Bernstein
  0 siblings, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2011-02-28  7:09 UTC (permalink / raw)
  To: zsh-workers

On Feb 28, 12:08am, Rocky Bernstein wrote:
}
} As for the typeset -T and typeset -p not showing -T associations, I think
} that's a misfeature.
} 
} Should I look into providing a patch for this?

I think first there needs to be a bit of discussion about what the result
should look like.

E.g. if I have

    typeset -T SCALAR=x:y:z array

and then I do

    typeset -p SCALAR
    typeset -p array

should I get the exact same output both times?

Also what should the value of $parameters[foo] look like?  My first idea
is something like

    array-tied:FOO

but there may be problems with that which I haven't foreseen.
 
} Saving an environment for reloading into another session, whether
} nested or not, might be useful in other contexts. Possibly the code
} you or I have in zshdb could be turned into a function and put inside
} the parameter module?

Until you mentioned the debugger, I was completely at a loss to come up
with an environment where you'd want to attempt to reload any parameter
that is normally maintained by the shell internals (such as any of the
variables in the $parameter module, or most of the other modules for
that matter).  I still can't think of one.

However, parameters that are marked "typeset -H" and thus have their
values suppressed in the typeset -p output can only be saved/restored
by tricks that would be better applied in a C function, so I can't
really argue against it.

} What I'm thinking of now is adding a function save_var which takes the
} name of a variable one wants to persist.

That makes a bit more sense, but in that case you have a list of the
names and can do

    for param in "${save_vars[@]}"
    do case $parameters[$param] in
       (*assoc*)
         print -- "typeset -A $param; $param=( ${(P@kvqq)param} )";;
       (*array*)
         print -- "typeset -a $param; $param=( ${(P@qq)param} )";;
       # etc.
    done > $the_save_file

The point being that one doesn't need to dump the entire output of
typeset, only the parameters whose names are explicitly known.

} If there is something like a tie function like there is in Perl or a
} discipline function on a varaible like ksh, that might be used, but
} this would be on a per-variable basis.

There's not, at this time.

} On Sun, Feb 27, 2011 at 4:01 PM, Bart Schaefer <schaefer@brasslantern.com>wrote:
} >
} >    () {
} >      local param type
} >      for param type in "${(kv@)parameters}"
} >      do
} >        case "$type" in
} >        (*local*) continue;;   # Skip loop variables
} >        (*export*) continue;;  # No need to dump/restore if exported?
} >        (*special*) continue;; # Maintained by the shell
} >        (*readonly*) continue;;
} >        (*) typeset -p "$param";;
} >        esac
} >      done
} >    }
} 
} But while we are being precise, let me point out that it is wrong to
} say that a local variable is a "loop" variable as you suggest in the
} code above.

I was referring to skipping "param" and "type", the variables for the loop
over ${(kv)parameters}.  There aren't any other locals in the anonymous
scope (though there could be in a surrounding scope).


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-02-28  7:09     ` Bart Schaefer
@ 2011-03-01  3:09       ` Rocky Bernstein
  2011-03-01  5:59         ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Rocky Bernstein @ 2011-03-01  3:09 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 6152 bytes --]

Comments in line. In sum, thanks again for the code suggestion. A modified
version of that I now use in the debugger.

On Mon, Feb 28, 2011 at 2:09 AM, Bart Schaefer <schaefer@brasslantern.com>wrote:

> On Feb 28, 12:08am, Rocky Bernstein wrote:
> }
> } As for the typeset -T and typeset -p not showing -T associations, I think
> } that's a misfeature.
> }
> } Should I look into providing a patch for this?
>
> I think first there needs to be a bit of discussion about what the result
> should look like.
>
> E.g. if I have
>
>    typeset -T SCALAR=x:y:z array
>
> and then I do
>
>    typeset -p SCALAR
>    typeset -p array
>
> should I get the exact same output both times?
>

I don't understand the complexity let alone the ramifications here. If you
think it worthwhile or if others may be as confused as I am please
elaborate. (But I am probably not qualified to judge.)

In my simple-minded way of thinking, if I had previously issued:
   typeset -T SCALAR=x:y:z array

then "typeset -p" I would imagine would print:
   typeset -T SCALAR=x:y:z array

what "typeset -p array" prints is another issue and dependent on the
definition of "array".



> Also what should the value of $parameters[foo] look like?  My first idea
> is something like
>
>    array-tied:FOO
>
> but there may be problems with that which I haven't foreseen.
>

Again, you are probably in a better position than most to know about those
problems. I imagine if anyone else on the list has something to add, they
will.

>From my standpoint, even if nothing is done here but just adding the
simple-minded "typeset -p" for the tied array/scalar is an improvement.



> } Saving an environment for reloading into another session, whether
> } nested or not, might be useful in other contexts. Possibly the code
> } you or I have in zshdb could be turned into a function and put inside
> } the parameter module?
>
> Until you mentioned the debugger, I was completely at a loss to come up
> with an environment where you'd want to attempt to reload any parameter
> that is normally maintained by the shell internals (such as any of the
> variables in the $parameter module, or most of the other modules for
> that matter).  I still can't think of one.
>

Alas again I am not sure I understand you here.

Something I think likely is that I am inside a zsh session I've been playing
around writing definitions and trying tests and setting variables and want
to save out the environment so that sometime later I can come back into zsh
and set things up roughly as they were before.

Or perhaps in order to send back a bug report I want someone else to be able
to see the
relations of things. They might have to edit parts of that environment, but
still the bulk of the settings would be relevant.


> However, parameters that are marked "typeset -H" and thus have their
> values suppressed in the typeset -p output can only be saved/restored
> by tricks that would be better applied in a C function, so I can't
> really argue against it.
>
> } What I'm thinking of now is adding a function save_var which takes the
> } name of a variable one wants to persist.
>
> That makes a bit more sense, but in that case you have a list of the
> names and can do
>
>    for param in "${save_vars[@]}"
>    do case $parameters[$param] in
>       (*assoc*)
>         print -- "typeset -A $param; $param=( ${(P@kvqq)param} )";;
>       (*array*)
>         print -- "typeset -a $param; $param=( ${(P@qq)param} )";;
>       # etc.
>    done > $the_save_file
>
> The point being that one doesn't need to dump the entire output of
> typeset, only the parameters whose names are explicitly known.
>

I never suggested on a *restore* everything would be saved, although now
that I think of it, that would have the advantage of obviating having the
user indicate which variables should persist.

For now, I'll go with the more manual approach. It may in fact be that folks
*don't* want changes they make to persist. Thing can always be changed
later.

I am kind of mixed on how much I want to use zsh-specific idioms, rather
than, say using
eval which may be clunkier but works on all of the POSIX shells. The more
shell-specific code I have, the more maintenance I have across the 3 POSIX
shell debuggers.

That said, the code you have above is more shell idiomatic than the kind of
thing I have been writing. I suspect there is much that could be improved in
the debugger because at heart I'm not that good of a POSIX shell
programmer.

I hope you don't take offense, but the code you have above is a little bit
wrong. We don't want to issue typeset commands because that will cause the
*scope* to change.

In a debugger, one is in trap function which then invoked the nested shell.
The restore is done in the trap hook -- specifically in the debugger's
"shell" command. But the original definition of the variable (if there is
one) that a programmer typically wants to change will not be in the hook,
but farther away the call chain in the debugged program.


> } If there is something like a tie function like there is in Perl or a
> } discipline function on a varaible like ksh, that might be used, but
> } this would be on a per-variable basis.
>
> There's not, at this time.
>
> } On Sun, Feb 27, 2011 at 4:01 PM, Bart Schaefer <
> schaefer@brasslantern.com>wrote:
> } >
> } >    () {
> } >      local param type
> } >      for param type in "${(kv@)parameters}"
> } >      do
> } >        case "$type" in
> } >        (*local*) continue;;   # Skip loop variables
> } >        (*export*) continue;;  # No need to dump/restore if exported?
> } >        (*special*) continue;; # Maintained by the shell
> } >        (*readonly*) continue;;
> } >        (*) typeset -p "$param";;
> } >        esac
> } >      done
> } >    }
> }
> } But while we are being precise, let me point out that it is wrong to
> } say that a local variable is a "loop" variable as you suggest in the
> } code above.
>
> I was referring to skipping "param" and "type", the variables for the loop
> over ${(kv)parameters}.  There aren't any other locals in the anonymous
> scope (though there could be in a surrounding scope).
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-03-01  3:09       ` Rocky Bernstein
@ 2011-03-01  5:59         ` Bart Schaefer
  2011-03-01  6:49           ` Rocky Bernstein
  0 siblings, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2011-03-01  5:59 UTC (permalink / raw)
  To: zsh-workers

On Feb 28, 10:09pm, Rocky Bernstein wrote:
}
} Comments in line. In sum, thanks again for the code suggestion.  A
} modified version of that I now use in the debugger.

You're welcome; glad to help.

} On Mon, Feb 28, 2011 at 2:09 AM, Bart Schaefer <schaefer@brasslantern.com>wrote:
} 
} > E.g. if I have
} >
} >    typeset -T SCALAR=x:y:z array
} >
} > and then I do
} >
} >    typeset -p SCALAR
} >    typeset -p array
} >
} > should I get the exact same output both times?
} 
} I don't understand the complexity let alone the ramifications here. If
} you think it worthwhile or if others may be as confused as I am please
} elaborate. (But I am probably not qualified to judge.)

Well ... internally ...

After "typeset -T SCALAR array" both SCALAR and array have the PM_TIED
flag set, and each of them records the name of the other one in the
ename field of the Param struct.  So theoretically when one asks for
the typeset form of either of them, there's enough information to
emit the correct typeset -T expression.  However, it's really only
the scalar that stores the assignable value and the optional join
character, so it takes an extra dereference to get from the name of
the array to the Param for the scalar that has all the data.

Upon "typeset -p array", then, the question is whether to discover
the PM_TIED flag, and therefore look up the name of SCALAR and act as
if "typeset -p SCALAR" had been invoked instead; or to just punt and
output an assignment for the array as if it were not tied.

When executing "typeset -p" with no other arguments the PM_TIED flag
could be ignored for arrays because the corresponding typeset for the
scalar is also going to be output.  That would make the entire dump
self-consistent for reloading, but would make the output for the
array incomplete if taken in isolation.  Which is the better course?

You, I presume, would argue for the reloadable dump rather than for
two assignments that are correct each alone but break when processed
together.

} In my simple-minded way of thinking, if I had previously issued:
}    typeset -T SCALAR=x:y:z array
} 
} then "typeset -p" I would imagine would print:
}    typeset -T SCALAR=x:y:z array

Hmm, perhaps it should output

    typeset -T SCALAR=x:y:z array :

to make the join character explicit.  Should the default be special-
cased, or not?

} what "typeset -p array" prints is another issue and dependent on the
} definition of "array".

It has to output one of two things.  Either

    typeset -a array
    array=(x y z)

Or

    typeset -T SCALAR=x:y:z array :
 
} > Until you mentioned the debugger, I was completely at a loss to come up
} > with an environment where you'd want to attempt to reload any parameter
} > that is normally maintained by the shell internals (such as any of the
} > variables in the $parameter module, or most of the other modules for
} > that matter).  I still can't think of one.
} 
} Alas again I am not sure I understand you here.

I'm drawing a distinction between parameters to which the programmer
has assigned values, and parameters for which the shell has in some
automated or default fashion populated the values.  I can understand
wanting to save and restore the former; the circumstances for the latter
are harder to invent (and most of those variables are readonly besides,
but not all).

} Something I think likely is that I am inside a zsh session I've been
} playing around writing definitions and trying tests and setting
} variables and want to save out the environment so that sometime later
} I can come back into zsh and set things up roughly as they were
} before.
} 
} Or perhaps in order to send back a bug report I want someone else
} to be able to see the relations of things. They might have to edit
} parts of that environment, but still the bulk of the settings would be
} relevant.

In both of those cases, though, there's a lot more that you need to
save/restore than just parameters.  There's a whole (lengthy) script
Util/reporter in the zsh distribution just for bug report purposes.
(It's been around a long time and probably needs updating.)
 
} >    for param in "${save_vars[@]}"
} >    do case $parameters[$param] in
} >       (*assoc*)
} >         print -- "typeset -A $param; $param=( ${(P@kvqq)param} )";;
} >       (*array*)
} >         print -- "typeset -a $param; $param=( ${(P@qq)param} )";;
} >       # etc.
} >    done > $the_save_file
} >
} > The point being that one doesn't need to dump the entire output of
} > typeset, only the parameters whose names are explicitly known.
} 
} I hope you don't take offense, but the code you have above is a little
} bit wrong.  We don't want to issue typeset commands because that will
} cause the *scope* to change.

No, no offense.  Unfortunately there's no way re-create an associative
array without issuing a "typeset -A" command first.  If scope is going
to be a problem, you need to figure out somehow whether what's needed
is to use "typeset -gA ...".  That might be a good argument for turning
this into C code, where you have access to the scoping level, etc.
 
} In a debugger, one is in trap function which then invoked the nested
} shell. The restore is done in the trap hook -- specifically in the
} debugger's "shell" command. But the original definition of the
} variable (if there is one) that a programmer typically wants to change
} will not be in the hook, but farther away the call chain in the
} debugged program.

Indeed, that's what I was talking about when I alluded to being "doomed
from the start" a couple of messages back in the thread ...


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-03-01  5:59         ` Bart Schaefer
@ 2011-03-01  6:49           ` Rocky Bernstein
  2011-03-01 15:15             ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Rocky Bernstein @ 2011-03-01  6:49 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 7513 bytes --]

Thanks for the information. The only thing I still don't understand or
disagree with is the "doomed from the start comment".

ksh introduced lexical scope for "function" kinds of functions, but I've not
seen lexical scope in zsh. It uses dynamic scoping; dynamic scope was
especially used in earlier versions of Lisp and was (is) the default for
Perl. ("my" was later added in Perl.)

In this kind of scope, it's sufficient to set the variable somewhere down
the call chain such as in the trace hook and that persists back to outside
the trace hook. I've tested this already in my nested shell example and it
works as expected. But of course here you have to be careful not to run some
sort of command that *defines* the variable again before the assignment or
else that will now be the point of a new scope for the variable's value.

So although on entry to the nested shell a definition of the type is either
necessary or useful, when writing a file on exit for later source'ing it is
not and is harmful: at the point in the debug hook where the values are
source'd back in to pick up changed values, an associative array's value has
already been defined scope-wise.

If one defines a *new* variable, that is, one that was not previously
defined before in the code being debugged, yes, there is no way to set that
down the call chain and have that picked up above where it might be intended
to be used.

But in the function which saves the variables I can probably check against
the original set of variables and give a warning (if this is an associative
array) that this kind of save is futile.


On Tue, Mar 1, 2011 at 12:59 AM, Bart Schaefer <schaefer@brasslantern.com>wrote:

> On Feb 28, 10:09pm, Rocky Bernstein wrote:
> }
> } Comments in line. In sum, thanks again for the code suggestion.  A
> } modified version of that I now use in the debugger.
>
> You're welcome; glad to help.
>
> } On Mon, Feb 28, 2011 at 2:09 AM, Bart Schaefer <
> schaefer@brasslantern.com>wrote:
> }
> } > E.g. if I have
> } >
> } >    typeset -T SCALAR=x:y:z array
> } >
> } > and then I do
> } >
> } >    typeset -p SCALAR
> } >    typeset -p array
> } >
> } > should I get the exact same output both times?
> }
> } I don't understand the complexity let alone the ramifications here. If
> } you think it worthwhile or if others may be as confused as I am please
> } elaborate. (But I am probably not qualified to judge.)
>
> Well ... internally ...
>
> After "typeset -T SCALAR array" both SCALAR and array have the PM_TIED
> flag set, and each of them records the name of the other one in the
> ename field of the Param struct.  So theoretically when one asks for
> the typeset form of either of them, there's enough information to
> emit the correct typeset -T expression.  However, it's really only
> the scalar that stores the assignable value and the optional join
> character, so it takes an extra dereference to get from the name of
> the array to the Param for the scalar that has all the data.
>
> Upon "typeset -p array", then, the question is whether to discover
> the PM_TIED flag, and therefore look up the name of SCALAR and act as
> if "typeset -p SCALAR" had been invoked instead; or to just punt and
> output an assignment for the array as if it were not tied.
>
> When executing "typeset -p" with no other arguments the PM_TIED flag
> could be ignored for arrays because the corresponding typeset for the
> scalar is also going to be output.  That would make the entire dump
> self-consistent for reloading, but would make the output for the
> array incomplete if taken in isolation.  Which is the better course?
>
> You, I presume, would argue for the reloadable dump rather than for
> two assignments that are correct each alone but break when processed
> together.
>
> } In my simple-minded way of thinking, if I had previously issued:
> }    typeset -T SCALAR=x:y:z array
> }
> } then "typeset -p" I would imagine would print:
> }    typeset -T SCALAR=x:y:z array
>
> Hmm, perhaps it should output
>
>    typeset -T SCALAR=x:y:z array :
>
> to make the join character explicit.  Should the default be special-
> cased, or not?
>
> } what "typeset -p array" prints is another issue and dependent on the
> } definition of "array".
>
> It has to output one of two things.  Either
>
>    typeset -a array
>    array=(x y z)
>
> Or
>
>    typeset -T SCALAR=x:y:z array :
>
> } > Until you mentioned the debugger, I was completely at a loss to come up
> } > with an environment where you'd want to attempt to reload any parameter
> } > that is normally maintained by the shell internals (such as any of the
> } > variables in the $parameter module, or most of the other modules for
> } > that matter).  I still can't think of one.
> }
> } Alas again I am not sure I understand you here.
>
> I'm drawing a distinction between parameters to which the programmer
> has assigned values, and parameters for which the shell has in some
> automated or default fashion populated the values.  I can understand
> wanting to save and restore the former; the circumstances for the latter
> are harder to invent (and most of those variables are readonly besides,
> but not all).
>
> } Something I think likely is that I am inside a zsh session I've been
> } playing around writing definitions and trying tests and setting
> } variables and want to save out the environment so that sometime later
> } I can come back into zsh and set things up roughly as they were
> } before.
> }
> } Or perhaps in order to send back a bug report I want someone else
> } to be able to see the relations of things. They might have to edit
> } parts of that environment, but still the bulk of the settings would be
> } relevant.
>
> In both of those cases, though, there's a lot more that you need to
> save/restore than just parameters.  There's a whole (lengthy) script
> Util/reporter in the zsh distribution just for bug report purposes.
> (It's been around a long time and probably needs updating.)
>
> } >    for param in "${save_vars[@]}"
> } >    do case $parameters[$param] in
> } >       (*assoc*)
> } >         print -- "typeset -A $param; $param=( ${(P@kvqq)param} )";;
> } >       (*array*)
> } >         print -- "typeset -a $param; $param=( ${(P@qq)param} )";;
> } >       # etc.
> } >    done > $the_save_file
> } >
> } > The point being that one doesn't need to dump the entire output of
> } > typeset, only the parameters whose names are explicitly known.
> }
> } I hope you don't take offense, but the code you have above is a little
> } bit wrong.  We don't want to issue typeset commands because that will
> } cause the *scope* to change.
>
> No, no offense.  Unfortunately there's no way re-create an associative
> array without issuing a "typeset -A" command first.  If scope is going
> to be a problem, you need to figure out somehow whether what's needed
> is to use "typeset -gA ...".  That might be a good argument for turning
> this into C code, where you have access to the scoping level, etc.
>
> } In a debugger, one is in trap function which then invoked the nested
> } shell. The restore is done in the trap hook -- specifically in the
> } debugger's "shell" command. But the original definition of the
> } variable (if there is one) that a programmer typically wants to change
> } will not be in the hook, but farther away the call chain in the
> } debugged program.
>
> Indeed, that's what I was talking about when I alluded to being "doomed
> from the start" a couple of messages back in the thread ...
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: typeset -p output gives shows variables which can't be read back in
  2011-03-01  6:49           ` Rocky Bernstein
@ 2011-03-01 15:15             ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 2011-03-01 15:15 UTC (permalink / raw)
  To: zsh-workers

On Mar 1,  1:49am, Rocky Bernstein wrote:
} 
} Thanks for the information. The only thing I still don't understand or
} disagree with is the "doomed from the start comment".

You agree but don't know why? :-)

E.g., if the shell you're debugging is six levels deep in function call
stack at the point where you decide to break out to a new shell, the
variables you dump are going to have several different dynamic scopes
which it will be impossible to recreate in the new shell.  It will
have defined functions which the new shell won't have (though allowing
$functions from zsh/parameter to be dumped and restored will get most
of them).  The option settings may not make sense in a top-level shell
and the traps certainly won't be restored.  Etc.
 
} In [dynamic] scope, it's sufficient to set the variable somewhere down
} the call chain such as in the trace hook and that persists back to
} outside the trace hook. I've tested this already in my nested shell
} example and it works as expected. But of course here you have to be
} careful not to run some sort of command that *defines* the variable
} again before the assignment or else that will now be the point of a
} new scope for the variable's value.

All true, but you can't simply assign to the name of an associative
array variable and have it behave like an associative array.  You MUST
declare it first, and you can't control whether it's already been
declared in some surrounding dynamic scope, so even typeset -g is not
enough to assure it will persist (and if it's been declared in some
surrounding scope, simple assignment will also change it in that scope
and not in the global one).

Hence "doomed" -- it's literally impossible to guarantee that you can
store variable state in a file and then restore it again, even to
replicate the state in a new shell.
 
} So although on entry to the nested shell a definition of the type is
} either necessary or useful, when writing a file on exit for later
} source'ing it is not and is harmful: at the point in the debug hook
} where the values are source'd back in to pick up changed values, an
} associative array's value has already been defined scope-wise.

I'm not sure how you assure the truth of that last statement, but you
must be working in a more constrained context than I'm imagining.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-03-01 15:15 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-27 11:44 typeset -p output gives shows variables which can't be read back in Rocky Bernstein
2011-02-27 21:01 ` Bart Schaefer
2011-02-28  5:08   ` Rocky Bernstein
2011-02-28  7:09     ` Bart Schaefer
2011-03-01  3:09       ` Rocky Bernstein
2011-03-01  5:59         ` Bart Schaefer
2011-03-01  6:49           ` Rocky Bernstein
2011-03-01 15:15             ` Bart Schaefer

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).