unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* SES local variables to define printers
@ 2013-05-23 20:52 Vincent Belaïche
  2013-05-23 21:35 ` Davis Herring
  2013-05-24  1:06 ` Glenn Morris
  0 siblings, 2 replies; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-23 20:52 UTC (permalink / raw)
  To: emacs-devel

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

Hello,

I have come across a ``regression'' in SES --- well I am not sure that
one can call it a ``regression'', let us rather say that one year ago it
was possible to play some borderline trick which is now no longer
possible with a recent EMACS.

That sort of trick was to define a file local variable foo to a lambda
expression defining a printer function, and then use the foo symbol as a
printer when setting the printer for a cell.

I wrote that this is a ``borderline trick'' because when you do that you
set the symbol-value of foo to the printer, and not its
symbol-function. But that was working --- I don't know why.

By the way, that kind of things was a security breach because you allow
to call a function defined in the file without any control. I suspect
that the root cause why this is no longer working is that EMACS has been
made more secure on that respect --- sorry I am not a regular lurker of
what is going on on this forum, so indeed I have no idea.

Now, I would like to have again the same sort of feature in SES, so I
did a quick hack herein attached --- there is a defcustom, so that the
user who re-enables this, does it at his/her own perils. But I am not
really satisfied with that patch --- so I did not commit it --- because
I think I should do more security checks if possible on the printer
function that is defined as a buffer local lambda expression.

So, I have a few questions to you experts:

- is that possible to check that a function do no border effect, like a
  SES printer function should do --- well, I presume, at least for
  buffer locally defined function --- anyway I would create some
  defcustom to deactivate that security check.

- is that possible to check that when a function is executing, that
  takes a reasonable time, and if not to interact with the use and ask
  whether he/she would like to double that time

VBR,
    Vincent.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: ses.el.diff --]
[-- Type: text/x-patch, Size: 2557 bytes --]

=== modified file 'lisp/ses.el'
--- lisp/ses.el	2013-01-02 16:13:04 +0000
+++ lisp/ses.el	2013-05-22 16:09:39 +0000
@@ -100,6 +100,26 @@
   :group 'ses
   :type 'hook)
 
+(defcustom ses-enable-local-variables nil
+  "Non-nil if SES should process local-variables lists in ses buffers.
+\(You can explicitly request processing the local-variables by
+executing `(hack-local-variables)'). Local variables are useful
+to define file local printers or values but raise a security
+issue if the printer function is used to do border effects. If
+you select `Filename test', then you should configure a function
+symbol or lambda expression which takes one argument, then the
+local variables are processed iff the buffer file name passed to
+this function returns a non nil. For instance you could configure:
+
+  (lambda (x)
+    (string-match \"^/dir/where/local/var/are/allowed\" 
+		  (expand-file-name x)))
+"
+  :type '(choice
+	  (const :tag "No" nil)
+	  (const :tag "Yes" t)
+	  (function :tag "Filename test"))
+  :group 'ses)
 
 ;;----------------------------------------------------------------------------
 ;; Global variables and constants
@@ -661,9 +681,11 @@
 
 (defun ses-printer-validate (printer)
   "Signal an error if PRINTER is not a valid SES cell printer."
+  
   (or (not printer)
       (stringp printer)
       (functionp printer)
+      (and (symbolp printer) (boundp printer) (functionp (symbol-value printer)))
       (and (stringp (car-safe printer)) (not (cdr printer)))
       (error "Invalid printer function"))
   printer)
@@ -1261,6 +1283,10 @@
 	    (format (car printer) value)
 	  ""))
        (t
+	(and (symbolp printer)
+	     (boundp printer)
+	     (functionp (symbol-value printer))
+	     (setq printer (symbol-value printer)))
 	(setq value (funcall printer (or value "")))
 	(if (stringp value)
 	    value
@@ -1899,9 +1925,17 @@
   (unless (and (boundp 'ses--deferred-narrow)
 	       (eq ses--deferred-narrow 'ses-mode))
     (kill-all-local-variables)
+    (setq major-mode 'ses-mode)
+    (and
+     enable-local-variables
+     ses-enable-local-variables
+     (or (eq ses-enable-local-variables t)
+	 (let ((bfn (buffer-file-name)))
+	   (and (stringp bfn)
+		(funcall ses-enable-local-variables bfn))))
+     (hack-local-variables))
     (ses-set-localvars)
-    (setq major-mode             'ses-mode
-	  mode-name              "SES"
+    (setq mode-name              "SES"
 	  next-line-add-newlines nil
 	  truncate-lines         t
 	  ;; SES deliberately puts lots of trailing whitespace in its buffer.


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

* Re: SES local variables to define printers
  2013-05-23 20:52 Vincent Belaïche
@ 2013-05-23 21:35 ` Davis Herring
  2013-05-24  1:06 ` Glenn Morris
  1 sibling, 0 replies; 20+ messages in thread
From: Davis Herring @ 2013-05-23 21:35 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> - is that possible to check that a function do no border effect, like a
>   SES printer function should do --- well, I presume, at least for
>   buffer locally defined function --- anyway I would create some
>   defcustom to deactivate that security check.

See `unsafep' (and the warning about display properties).

> - is that possible to check that when a function is executing, that
>   takes a reasonable time, and if not to interact with the use and ask
>   whether he/she would like to double that time

There is `with-timeout', but it's not much better than just letting the
user use C-g.

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.



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

* Re: SES local variables to define printers
  2013-05-23 20:52 Vincent Belaïche
  2013-05-23 21:35 ` Davis Herring
@ 2013-05-24  1:06 ` Glenn Morris
  1 sibling, 0 replies; 20+ messages in thread
From: Glenn Morris @ 2013-05-24  1:06 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel


I haven't quite followed what you are trying to do (I don't know what a
SES "printer" is), but as a general comment: please, please don't
(re)invent your own version of local variable handling unless you are
really, really sure you need special handling that is not provided by
normal file or directory local variables (or local eval). (And be really
careful if you do implement it, since it can be a security hole.)


Vincent Belaïche wrote:

> That sort of trick was to define a file local variable foo to a lambda
> expression defining a printer function, and then use the foo symbol as a
> printer when setting the printer for a cell.
[...]
> By the way, that kind of things was a security breach because you allow
> to call a function defined in the file without any control.

!!!

> Now, I would like to have again the same sort of feature in SES,

!!!

> so I did a quick hack herein attached 

!!!

"Security breach" + "quick hack" = fun times

> - is that possible to check that when a function is executing, that
>   takes a reasonable time, and if not to interact with the use and ask
>   whether he/she would like to double that time

   Your printer function `(lambda (arg) (shell-command "rm -rf /"))'
   has been running for 30 seconds.  Run for another 60?

Doesn't help much...

> +(defcustom ses-enable-local-variables nil
> +  "Non-nil if SES should process local-variables lists in ses buffers.

Why is this needed - what's wrong with the normal enable-local-variables?
Why should there be a special variable that controls local variables
only in SES files?

> +\(You can explicitly request processing the local-variables by
> +executing `(hack-local-variables)'). Local variables are useful
> +to define file local printers or values but raise a security
> +issue if the printer function is used to do border effects. If
> +you select `Filename test', then you should configure a function
> +symbol or lambda expression which takes one argument, then the
> +local variables are processed iff the buffer file name passed to

Don't use "iff" in doc strings.

> +this function returns a non nil. For instance you could configure:

"returns non-nil".

> +  (lambda (x)
> +    (string-match \"^/dir/where/local/var/are/allowed\" 
> +		  (expand-file-name x)))

Sounds like dir-locals.  Why not just use a dir-locals file?

> +"
> +  :type '(choice
> +	  (const :tag "No" nil)
> +	  (const :tag "Yes" t)
> +	  (function :tag "Filename test"))
> +  :group 'ses)

You would need to add

   :risky t

>        (functionp printer)
> +      (and (symbolp printer) (boundp printer) (functionp (symbol-value printer)))

What is this for?

> +	(and (symbolp printer)
> +	     (boundp printer)
> +	     (functionp (symbol-value printer))
> +	     (setq printer (symbol-value printer)))

? Likewise.

>  	(setq value (funcall printer (or value "")))
>  	(if (stringp value)
>  	    value
> @@ -1899,9 +1925,17 @@
>    (unless (and (boundp 'ses--deferred-narrow)
>  	       (eq ses--deferred-narrow 'ses-mode))
>      (kill-all-local-variables)
> +    (setq major-mode 'ses-mode)
> +    (and
> +     enable-local-variables
> +     ses-enable-local-variables
> +     (or (eq ses-enable-local-variables t)
> +	 (let ((bfn (buffer-file-name)))
> +	   (and (stringp bfn)
> +		(funcall ses-enable-local-variables bfn))))

Ironically, ses-enable-local-variables is itself a potential security hole...



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

* Re: SES local variables to define printers
@ 2013-05-24  5:45 Vincent Belaïche
  2013-05-24 13:28 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-24  5:45 UTC (permalink / raw)
  To: emacs-devel, rgm; +Cc: Vincent Belaïche

Answers embedded below:

> From: rgm@gnu.org
> To: vincent.b.1@hotmail.fr
> CC: emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> Date: Thu, 23 May 2013 21:06:45 -0400
> 
> 
> I haven't quite followed what you are trying to do (I don't know what a
> SES "printer" is), 

"SES Printers" are functions which take some cell value (like an integer
or a string, or whatever lisp object may be stored in a cell) at input
and return a string at output, that string is then align, fill or
truncated and displayed in a cell.

Customizing SES printer allows to do some fancy display for some cells
(e.g. display *like this* when the value is out of some bound).

> but as a general comment: please, please don't (re)invent your own
> version of local variable handling unless you are really, really sure
> you need special handling that is not provided by normal file or
> directory local variables (or local eval). 

I don't want to reinvent the wheel, this is exactly why I am not
satisfied with the hack which I did, and I am seeking guidance on this
forum. 

> (And be really careful if you do implement it, since it can be a
> security hole.)
> 

I am well aware of that, I won't commit anything before being sure that
it is in-line with EMACS general security policy.

> 
> Vincent Belaïche wrote:
> 
> > That sort of trick was to define a file local variable foo to a lambda
> > expression defining a printer function, and then use the foo symbol as a
> > printer when setting the printer for a cell.
> [...]
> > By the way, that kind of things was a security breach because you allow
> > to call a function defined in the file without any control.
> 
> !!!
> 

Yes, I fully agree with the "!!!", but this is what was there with emacs
23.xx or so. When I used that possibility the first time I did not
really realize that this could be a hold for malicious spreadsheets.


> > Now, I would like to have again the same sort of feature in SES,
> 
> !!!
> 

Yes, I would like the same possibility to define file local printer
function, but with less security hazards and more user control.

> > so I did a quick hack herein attached 
> 
> !!!
> 
> "Security breach" + "quick hack" = fun times
> 

I needed the feature really urgently, so I did that only for myself, I
do not recommend the patch attached for incorporating that into official
EMACS.


> > - is that possible to check that when a function is executing, that
> > takes a reasonable time, and if not to interact with the use and ask
> > whether he/she would like to double that time
> 
> Your printer function `(lambda (arg) (shell-command "rm -rf /"))'
> has been running for 30 seconds. Run for another 60?
> 
> Doesn't help much...
> 

Typically you would have checked that the printer function does not do
any potential border effect in the first place, so a function calling
`shell-command' would have been screened for that before being
called. The case which would like to prevent if function with infinite
loops that simply would get the user stuck, but without doing much harm
--- well they could also clutter the heap, so maybe that should also be
checked that the function does not take too much memory.

> > +(defcustom ses-enable-local-variables nil
> > + "Non-nil if SES should process local-variables lists in ses buffers.
> 
> Why is this needed - what's wrong with the normal enable-local-variables?
> Why should there be a special variable that controls local variables
> only in SES files?
> 

With this additional variable you may allow to have file local variables
for some type of variables like calc-float-format or calc-number-radix
that influence that way some formatting function process their input,
but at the same time prevent any file local printer functions.

> > +\(You can explicitly request processing the local-variables by
> > +executing `(hack-local-variables)'). Local variables are useful
> > +to define file local printers or values but raise a security
> > +issue if the printer function is used to do border effects. If
> > +you select `Filename test', then you should configure a function
> > +symbol or lambda expression which takes one argument, then the
> > +local variables are processed iff the buffer file name passed to
> 
> Don't use "iff" in doc strings.
> 

Ok, that is not English, neither I am ;-)...

> > +this function returns a non nil. For instance you could configure:
> 
> "returns non-nil".
> 
> > + (lambda (x)
> > + (string-match \"^/dir/where/local/var/are/allowed\" 
> > + (expand-file-name x)))
> 
> Sounds like dir-locals. Why not just use a dir-locals file?
> 

Simply because I did not know about dir-locals. You mean info node
`(emacs) Directory Variables'. 

Well, I agree that this would help in the case for which I needed that
hack. But in essence, whether the variable is defined locally to a
directory or for a single file does not per se solve all security
issues: imagine that you download from the Internet a whole tar-zipped
directory tree and you have some malicious printer functions defined
dir-locally in this tree, then you would still have the issue. With the
defcustom you check that 

> > +"
> > + :type '(choice
> > + (const :tag "No" nil)
> > + (const :tag "Yes" t)
> > + (function :tag "Filename test"))
> > + :group 'ses)
> 
> You would need to add
> 
> :risky t
> 

Yes, you are right. Anyway the first thing we should solve is whether
there is not a better way to do that, and how to do some checks on that
printer function to guess whether it can be malicious or not.

> > (functionp printer)
> > + (and (symbolp printer) (boundp printer) (functionp (symbol-value printer)))
> 
> What is this for?
> 


In that case printer is not a function but a symbol pointing at a file
local variable, and the "value" slot of this symbol is what contains the
printer function.

> > + (and (symbolp printer)
> > + (boundp printer)
> > + (functionp (symbol-value printer))
> > + (setq printer (symbol-value printer)))
> 
> ? Likewise.
> 

Same answer.

> > (setq value (funcall printer (or value "")))
> > (if (stringp value)
> > value
> > @@ -1899,9 +1925,17 @@
> > (unless (and (boundp 'ses--deferred-narrow)
> > (eq ses--deferred-narrow 'ses-mode))
> > (kill-all-local-variables)
> > + (setq major-mode 'ses-mode)
> > + (and
> > + enable-local-variables
> > + ses-enable-local-variables
> > + (or (eq ses-enable-local-variables t)
> > + (let ((bfn (buffer-file-name)))
> > + (and (stringp bfn)
> > + (funcall ses-enable-local-variables bfn))))
> 
> Ironically, ses-enable-local-variables is itself a potential security hole...

Yes, you are right I have to tag this variable as not to be set
file-locally, I missed that one, thank you for suggesting the `:risky
t'.

   Vincent.



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

* Re: SES local variables to define printers
@ 2013-05-24  5:46 Vincent Belaïche
  0 siblings, 0 replies; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-24  5:46 UTC (permalink / raw)
  To: emacs-devel, rgm

Answers embedded below:

> From: rgm@gnu.org
> To: vincent.b.1@hotmail.fr
> CC: emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> Date: Thu, 23 May 2013 21:06:45 -0400
> 
> 
> I haven't quite followed what you are trying to do (I don't know what a
> SES "printer" is), 

"SES Printers" are functions which take some cell value (like an integer
or a string, or whatever lisp object may be stored in a cell) at input
and return a string at output, that string is then align, fill or
truncated and displayed in a cell.

Customizing SES printer allows to do some fancy display for some cells
(e.g. display *like this* when the value is out of some bound).

> but as a general comment: please, please don't (re)invent your own
> version of local variable handling unless you are really, really sure
> you need special handling that is not provided by normal file or
> directory local variables (or local eval). 

I don't want to reinvent the wheel, this is exactly why I am not
satisfied with the hack which I did, and I am seeking guidance on this
forum. 

> (And be really careful if you do implement it, since it can be a
> security hole.)
> 

I am well aware of that, I won't commit anything before being sure that
it is in-line with EMACS general security policy.

> 
> Vincent Belaïche wrote:
> 
> > That sort of trick was to define a file local variable foo to a lambda
> > expression defining a printer function, and then use the foo symbol as a
> > printer when setting the printer for a cell.
> [...]
> > By the way, that kind of things was a security breach because you allow
> > to call a function defined in the file without any control.
> 
> !!!
> 

Yes, I fully agree with the "!!!", but this is what was there with emacs
23.xx or so. When I used that possibility the first time I did not
really realize that this could be a hold for malicious spreadsheets.


> > Now, I would like to have again the same sort of feature in SES,
> 
> !!!
> 

Yes, I would like the same possibility to define file local printer
function, but with less security hazards and more user control.

> > so I did a quick hack herein attached 
> 
> !!!
> 
> "Security breach" + "quick hack" = fun times
> 

I needed the feature really urgently, so I did that only for myself, I
do not recommend the patch attached for incorporating that into official
EMACS.


> > - is that possible to check that when a function is executing, that
> > takes a reasonable time, and if not to interact with the use and ask
> > whether he/she would like to double that time
> 
> Your printer function `(lambda (arg) (shell-command "rm -rf /"))'
> has been running for 30 seconds. Run for another 60?
> 
> Doesn't help much...
> 

Typically you would have checked that the printer function does not do
any potential border effect in the first place, so a function calling
`shell-command' would have been screened for that before being
called. The case which would like to prevent if function with infinite
loops that simply would get the user stuck, but without doing much harm
--- well they could also clutter the heap, so maybe that should also be
checked that the function does not take too much memory.

> > +(defcustom ses-enable-local-variables nil
> > + "Non-nil if SES should process local-variables lists in ses buffers.
> 
> Why is this needed - what's wrong with the normal enable-local-variables?
> Why should there be a special variable that controls local variables
> only in SES files?
> 

With this additional variable you may allow to have file local variables
for some type of variables like calc-float-format or calc-number-radix
that influence that way some formatting function process their input,
but at the same time prevent any file local printer functions.

> > +\(You can explicitly request processing the local-variables by
> > +executing `(hack-local-variables)'). Local variables are useful
> > +to define file local printers or values but raise a security
> > +issue if the printer function is used to do border effects. If
> > +you select `Filename test', then you should configure a function
> > +symbol or lambda expression which takes one argument, then the
> > +local variables are processed iff the buffer file name passed to
> 
> Don't use "iff" in doc strings.
> 

Ok, that is not English, neither I am ;-)...

> > +this function returns a non nil. For instance you could configure:
> 
> "returns non-nil".
> 
> > + (lambda (x)
> > + (string-match \"^/dir/where/local/var/are/allowed\" 
> > + (expand-file-name x)))
> 
> Sounds like dir-locals. Why not just use a dir-locals file?
> 

Simply because I did not know about dir-locals. You mean info node
`(emacs) Directory Variables'. 

Well, I agree that this would help in the case for which I needed that
hack. But in essence, whether the variable is defined locally to a
directory or for a single file does not per se solve all security
issues: imagine that you download from the Internet a whole tar-zipped
directory tree and you have some malicious printer functions defined
dir-locally in this tree, then you would still have the issue. With the
defcustom you check that 

> > +"
> > + :type '(choice
> > + (const :tag "No" nil)
> > + (const :tag "Yes" t)
> > + (function :tag "Filename test"))
> > + :group 'ses)
> 
> You would need to add
> 
> :risky t
> 

Yes, you are right. Anyway the first thing we should solve is whether
there is not a better way to do that, and how to do some checks on that
printer function to guess whether it can be malicious or not.

> > (functionp printer)
> > + (and (symbolp printer) (boundp printer) (functionp (symbol-value printer)))
> 
> What is this for?
> 


In that case printer is not a function but a symbol pointing at a file
local variable, and the "value" slot of this symbol is what contains the
printer function.

> > + (and (symbolp printer)
> > + (boundp printer)
> > + (functionp (symbol-value printer))
> > + (setq printer (symbol-value printer)))
> 
> ? Likewise.
> 

Same answer.

> > (setq value (funcall printer (or value "")))
> > (if (stringp value)
> > value
> > @@ -1899,9 +1925,17 @@
> > (unless (and (boundp 'ses--deferred-narrow)
> > (eq ses--deferred-narrow 'ses-mode))
> > (kill-all-local-variables)
> > + (setq major-mode 'ses-mode)
> > + (and
> > + enable-local-variables
> > + ses-enable-local-variables
> > + (or (eq ses-enable-local-variables t)
> > + (let ((bfn (buffer-file-name)))
> > + (and (stringp bfn)
> > + (funcall ses-enable-local-variables bfn))))
> 
> Ironically, ses-enable-local-variables is itself a potential security hole...

Yes, you are right I have to tag this variable as not to be set
file-locally, I missed that one, thank you for suggesting the `:risky
t'.

   Vincent.



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

* Re: SES local variables to define printers
@ 2013-05-24  5:53 Vincent Belaïche
  0 siblings, 0 replies; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-24  5:53 UTC (permalink / raw)
  To: emacs-devel, herring

Answers below

> Date: Thu, 23 May 2013 15:35:51 -0600
> From: herring@lanl.gov
> To: vincent.b.1@hotmail.fr
> CC: emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> 
> > - is that possible to check that a function do no border effect, like a
> > SES printer function should do --- well, I presume, at least for
> > buffer locally defined function --- anyway I would create some
> > defcustom to deactivate that security check.
> 
> See `unsafep' (and the warning about display properties).
> 

I will have a look, thanks for pointing at that.

> > - is that possible to check that when a function is executing, that
> > takes a reasonable time, and if not to interact with the use and ask
> > whether he/she would like to double that time
> 
> There is `with-timeout', but it's not much better than just letting the
> user use C-g.
> 

My intent is to keep the spread sheet in consistent state as as much as
possible. As printing is deferred from cell formula value processing and
reference inferring, a break during printing should not cause too much
harm, but I have to check that with some intentionnally long printing.

> Davis
> 
   Vincent.

> -- 
> This product is sold by volume, not by mass. If it appears too dense or
> too sparse, it is because mass-energy conversion has occurred during
> shipping.

Do you mean something like an obese chicken crossing the Atlantic ocean
on a rowing boat ? Well, that can't be that: chicken are not thing, but
they are living creatures ! --- and, besidesn they are not very good at
rowing.



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

* Re: SES local variables to define printers
  2013-05-24  5:45 Vincent Belaïche
@ 2013-05-24 13:28 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-24 13:28 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

Hi Vincent,

Could you show us an example of what used to work, as well as an example
of what you'd ideally want to see working (in case it's different)?


        Stefan



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

* Re: SES local variables to define printers
@ 2013-05-25 20:43 Vincent Belaïche
  2013-05-26  1:17 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-25 20:43 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

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

Stefan Monnier a écrit :
> Hi Vincent,
>
> Could you show us an example of what used to work, as well as an example
> of what you'd ideally want to see working (in case it's different)?
>
>
>         Stefan
>

Here is an example "example.ses", if you open it with the current SES it
will generate an error "Invalid printer" while it used to work --- don't
remember with which version, but that sort of thing was working one year
or so ago.

If you take my patch (attached as ses.el.gz) and configure
ses-enable-local-variables you will have desired printing.

The thing is that I often use Calc object in cells --- and this is even
the very reason why I use SES --- the downside of that is that I need to
configure suitable printing functions for those Calc objects --- this is
all the more true that some time I happen not to have the same float
format for all the cells.

Another use case is that in some cell I have to be confirmed values
(some guess which I need to reconfirm...) and I want some printing with
some mark that this cell needs to be consolidated.

In the attached example I use two local printers checked-time and
tbc-time: cells B2 -- B4 use checked-time, while cells B5 & B6 use
tbc-time. check-time does some fancy printing for Calc HMS forms, and
tbc-time add some extra "?? " prefix on top of that. So I get this
display:

-----Task------ -----Time------
      gardening        1h 3m 0s
        cooking     0h 45m 3.1s
       sleeping       7h 35m 6s
  bird watching    ?? 0h 20m 0s
        *Total*  ?? 9h 43m 9.1s

BR,
   Vincent.


[-- Attachment #2: example.ses --]
[-- Type: text/plain, Size: 1364 bytes --]

-----Task------ -----Time------
      gardening        1h 3m 0s
        cooking     0h 45m 3.1s
       sleeping       7h 35m 6s
  bird watching    ?? 0h 20m 0s
        *Total*  ?? 9h 43m 9.1s

\f
(ses-cell A1 "Task" "Task" ses-dashfill nil)
(ses-cell B1 "Time" "Time" ses-dashfill nil)

(ses-cell A2 "gardening" "gardening" nil nil)
(ses-cell B2 (hms 1 3 0) (quote (hms 1 3 0)) checked-time (B6))

(ses-cell A3 "cooking" "cooking" nil nil)
(ses-cell B3 (hms 0 45 (float 312 -2)) (quote (hms 0 45 (float 312 -2))) checked-time (B6))

(ses-cell A4 "sleeping" "sleeping" nil nil)
(ses-cell B4 (hms 7 35 6) (quote (hms 7 35 6)) checked-time (B6))

(ses-cell A5 "bird watching" "bird watching" nil nil)
(ses-cell B5 (hms 0 20 0) (quote (hms 0 20 0)) tbc-time (B6))

(ses-cell A6 "*Total*" "*Total*" nil nil)
(ses-cell B6 (hms 9 43 (float 912 -2)) (calcFunc-add B2 B3 B4 B5) tbc-time nil)

(ses-column-widths [15 15])
(ses-column-printers [nil nil])
(ses-default-printer "%.7g")
(ses-header-row 0)

( ;Global parameters (these are read first)
 2 ;SES file-format
 6 ;numrows
 2 ;numcols
)

;; Local Variables:
;; mode: ses
;; checked-time: (lambda (x) (let ((calc-float-format '(fix 1)) (calc-hms-format "%sh %sm %ss")) (math-format-value x)))
;; tbc-time: (lambda (x) (let ((calc-float-format '(fix 1))(calc-hms-format "?? %sh %sm %ss")) (math-format-value x)))
;; End:

[-- Attachment #3: ses.el.gz --]
[-- Type: application/octet-stream, Size: 37599 bytes --]

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

* Re: SES local variables to define printers
  2013-05-25 20:43 SES local variables to define printers Vincent Belaïche
@ 2013-05-26  1:17 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-26  1:17 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> Here is an example "example.ses", if you open it with the current SES it
> will generate an error "Invalid printer" while it used to work --- don't
> remember with which version, but that sort of thing was working one year
> or so ago.

It doesn't work with any of Debian's Emacs-24.1, Emacs-23.4, or
Emacs-22.3.  It must have been something different.

> If you take my patch (attached as ses.el.gz) and configure
> ses-enable-local-variables you will have desired printing.

How 'bout:

You add to your .emacs

   (defun my-checked-time (x)
     (let ((calc-float-format '(fix 1)) (calc-hms-format "%sh %sm %ss"))
       (math-format-value x)))
   (defun my-tbc-time (x)
     (let ((calc-float-format '(fix 1))(calc-hms-format "?? %sh %sm %ss"))
       (math-format-value x)))

and then you can use those printer functions in your ses files.

It's simple and safe, and it works without any changes.


        Stefan



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

* RE: SES local variables to define printers
@ 2013-05-26  7:16 Vincent Belaïche
  2013-05-26 18:02 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-26  7:16 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel; +Cc: Vincent Belaïche



> From: monnier@iro.umontreal.ca
> To: vincent.b.1@hotmail.fr
> CC: emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> Date: Sat, 25 May 2013 21:17:10 -0400
> 
> > Here is an example "example.ses", if you open it with the current SES it
> > will generate an error "Invalid printer" while it used to work --- don't
> > remember with which version, but that sort of thing was working one year
> > or so ago.
> 
> It doesn't work with any of Debian's Emacs-24.1, Emacs-23.4, or
> Emacs-22.3. It must have been something different.
> 

Well, since that was 1 year ago or so that I was using this sheet I may
have done some hack at that time... sorry for the bold assertion that
this *WAS wORKING*, I must admit that I am not so sure now.

Now, having thought a bit more about it, I think that in most sheets I
have the local variables my-tbc-time and my-checked-time defined as
local variables, and the printer function defined as e.g. (lambda (x)
(funcall my-tbc-time x)) rather than just my-tbc-time. 

I don't know why in the faulty one-year-old-sheet it was done with just
my-tbc-time for the printer. Probably I had the symbol-function slot
also defined somewhere else --- like in my *scratch* --- to the same
function and that was hiding that defining locally the function in the
value slot was not working.

> > If you take my patch (attached as ses.el.gz) and configure
> > ses-enable-local-variables you will have desired printing.
> 
> How 'bout:
> 
> You add to your .emacs
> 
> (defun my-checked-time (x)
> (let ((calc-float-format '(fix 1)) (calc-hms-format "%sh %sm %ss"))
> (math-format-value x)))
> (defun my-tbc-time (x)
> (let ((calc-float-format '(fix 1))(calc-hms-format "?? %sh %sm %ss"))
> (math-format-value x)))
> 
> and then you can use those printer functions in your ses files.
> 
> It's simple and safe, and it works without any changes.
> 
> 

Well, it also means that your .emacs will grow endlessly as you create
new sheets, and also that you cannot archive the sheet+printer in the
same batch easily. Definitely I would not buy this one.

Maybe another way would be to use ede mode, and to  have the printer
functions defined in some prj.el file. I must admit that I am not an
experienced user of ede, I use it only inderectly through JDEE and I am
not well aware of how ede ensures security.

Anyway there could be some safe macro ses-printer-def placed in the EDE
prj.el file to define needed printer functions, and ses-printer-def
would make some check that the printer uses only functions without
border effect and without any loop structure.

Anyway, the simpler is to have printer functions configured as:

 (lambda (x) (funcall my-tbc-time x))

> Stefan

   Vincent.



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

* Re: SES local variables to define printers
  2013-05-26  7:16 Vincent Belaïche
@ 2013-05-26 18:02 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-26 18:02 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> Well, it also means that your .emacs will grow endlessly as you create
> new sheets, and also that you cannot archive the sheet+printer in the
> same batch easily.

I find it odd that the set of printer functions would grow endlessly
with the number of sheets; I'd expect there to be a fairly limited
number of them, but maybe they differ in "minor" details.

But it sounds like you'd want to extend SES so that you can store/share
definitions of functions in the SES file.

E.g. when you do `p (lambda (...)) RET' SES could immediately ask you to
name that function and save the result somewhere in the file.

> border effect and without any loop structure.

Actually, loop structure doesn't sound problematic w.r.t safety.


        Stefan



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

* Re: SES local variables to define printers
@ 2013-05-26 20:25 Vincent Belaïche
  2013-05-27  1:35 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-26 20:25 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

Stefan Monnier a écrit :
>> Well, it also means that your .emacs will grow endlessly as you create
>> new sheets, and also that you cannot archive the sheet+printer in the
>> same batch easily.
>
> I find it odd that the set of printer functions would grow endlessly
> with the number of sheets; I'd expect there to be a fairly limited
> number of them, but maybe they differ in "minor" details.
>

Well, mainly some surounding of the information, some number formatting,
etc... as you have a great number of possible combinations, that would
really make things grow endlessly.

In fact I think that the simplest/safest way would be if the printer
would be some string, that SES would interprete to build the
function. The thing is that I need to extend the format %d %f and on on
to cover Calc objects. This is something which I had already being
thinking about for some time, but I have not yet dared go into it.

> But it sounds like you'd want to extend SES so that you can store/share
> definitions of functions in the SES file.
>
> E.g. when you do `p (lambda (...)) RET' SES could immediately ask you to
> name that function and save the result somewhere in the file.
>

That would not really make it safer because any hacker could find the
`somewhere in the file' and put some malicious definition there.

>> border effect and without any loop structure.
>
> Actually, loop structure doesn't sound problematic w.r.t safety.
>
>

My concern was more about getting the system stuck, but you still have
the C-g

>         Stefan
>

  Vincent.



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

* Re: SES local variables to define printers
  2013-05-26 20:25 Vincent Belaïche
@ 2013-05-27  1:35 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-27  1:35 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> That would not really make it safer because any hacker could find the
> `somewhere in the file' and put some malicious definition there.

You'd check the function's safety when reading the file, of course, as
it is done currently for the `printer' arg of ses-cell.

> My concern was more about getting the system stuck, but you still have
> the C-g

Exactly: it allows denial-of-service kinds of attacks, but you can
probably already get similar problems some other way (e.g. provide
a `printer' argument that's a circular structure, so that the safety
checking doesn't terminate).


        Stefan



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

* RE: SES local variables to define printers
@ 2013-05-28  4:38 Vincent Belaïche
  2013-05-28  4:57 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-28  4:38 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel



> From: monnier@iro.umontreal.ca
> To: vincent.b.1@hotmail.fr
> Subject: Re: SES local variables to define printers
> Date: Sun, 26 May 2013 21:35:49 -0400
> CC: emacs-devel@gnu.org
> 
> > That would not really make it safer because any hacker could find the
> > `somewhere in the file' and put some malicious definition there.
> 
> You'd check the function's safety when reading the file, of course, as
> it is done currently for the `printer' arg of ses-cell.
> 
> > My concern was more about getting the system stuck, but you still have
> > the C-g
> 
> Exactly: it allows denial-of-service kinds of attacks, but you can
> probably already get similar problems some other way (e.g. provide
> a `printer' argument that's a circular structure, so that the safety
> checking doesn't terminate).
> 
> 
> Stefan
>

Just to recap your suggestion:

- the user would call some ses-define-local-printer interactive command,
  and would enter some symbol and body 

- the symbol to function would be saved in some hashmap or alist, or
  somthing like that, and saved in some special slot in the sheet, like
  at the end of the sheet where you can column count and row count, or
  like in a file local variable (second is probably the simplest, let us
  not re-invent the wheel).

- each time the user wants to set a printer, he/she can set the printer
  function symbol to mean a sheet local printer

- when a sheet is loaded, the local printer alist is loaded --- like any
  file local variable if local variables is what is used to define file
  local printers.

BR,
   Vincent.



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

* Re: SES local variables to define printers
  2013-05-28  4:38 Vincent Belaïche
@ 2013-05-28  4:57 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-28  4:57 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> - the user would call some ses-define-local-printer interactive command,
>   and would enter some symbol and body 

Not even.  He could just use the normal `p' (ses-read-cell-printer)
command and enter a lambda expression.  In response SES would offer to
give it a name and ask the user what name to use.

> - the symbol to function would be saved in some hashmap or alist, or
>   somthing like that, and saved in some special slot in the sheet, like
>   at the end of the sheet where you can column count and row count, or
>   like in a file local variable (second is probably the simplest, let us
>   not re-invent the wheel).

I'd add it to the file as a (ses-define-local-printer ..) call alongside
the various (ses-cell ...) calls.  But if you want to use a file-local
variable, that's fine as well (tho there might be size-limit issues
with using file-local variables).


        Stefan



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

* Re: SES local variables to define printers
@ 2013-05-30  5:50 Vincent Belaïche
  2013-05-30 13:20 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-30  5:50 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel



> From: monnier@iro.umontreal.ca

[...]

 
> I'd add it to the file as a (ses-define-local-printer ..) call alongside
> the various (ses-cell ...) calls. But if you want to use a file-local
> variable, that's fine as well (tho there might be size-limit issues
> with using file-local variables).
> 

Ok you means _after_ the ses-cell declaration, just before those general
declarations (taken from examples.ses):

(ses-column-widths [15 15])
(ses-column-printers [nil nil])
(ses-default-printer "%.7g")
(ses-header-row 0)

> 
> Stefan
>

   Vincent



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

* Re: SES local variables to define printers
@ 2013-05-30  7:24 Vincent Belaïche
  0 siblings, 0 replies; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-30  7:24 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

Replying to myself...

> From: vincent.b.1@hotmail.fr
> To: monnier@iro.umontreal.ca; emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> Date: Thu, 30 May 2013 07:50:08 +0200
> 

[...]

> 
> Ok you means _after_ the ses-cell declaration, just before those general
> declarations (taken from examples.ses):
> 
> (ses-column-widths [15 15])
> (ses-column-printers [nil nil])
> (ses-default-printer "%.7g")
> (ses-header-row 0)
> 

[...]

One more question: when you define a symbol as local (e.g. with
make-local-variable), does it mean only the value slot of the symbol is
made local, or do you have also the function slot made local.

The hack which I have done also consisted in allowing to use the value
slot to define a function. That was just because file local variables
affect only the value slot, not the function slot. But on the other
hand, I am not even sure that EMACS lisp allow to create file local
functions.

What I could do if there is no such a thing as file local function is to
set the symbol value slot to some specific symbol, say :ses-printer, and
use the symbol name as a key to a hash map containing all local
printers.

   Vincent.





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

* Re: SES local variables to define printers
  2013-05-30  5:50 Vincent Belaïche
@ 2013-05-30 13:20 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-30 13:20 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> Ok you means _after_ the ses-cell declaration, just before those general
> declarations (taken from examples.ses):

For example.  I don't think it matters much whether they come after or
before the ses-cell calls.

> One more question: when you define a symbol as local (e.g. with
> make-local-variable), does it mean only the value slot of the symbol is
> made local, or do you have also the function slot made local.

It only defines this dynamically-bound variable as buffer-local.
The function is unaffected.

> hand, I am not even sure that EMACS lisp allow to create file local
> functions.

Elisp doesn't have buffer-local functions, indeed.

> What I could do if there is no such a thing as file local function is to
> set the symbol value slot to some specific symbol, say :ses-printer, and
> use the symbol name as a key to a hash map containing all local
> printers.

Actually, you don't need to use the symbol at all.
In ses-cell, just check if the printer's name is found in your hash-map
and if so, use the function you found there instead.

This way, the user can give local names without having to worry about
affecting other packages which might accidentally be using the
same names.


        Stefan



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

* RE: SES local variables to define printers
@ 2013-05-30 15:36 Vincent Belaïche
  2013-05-30 17:15 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Vincent Belaïche @ 2013-05-30 15:36 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel; +Cc: Vincent Belaïche



> From: monnier@iro.umontreal.ca
> To: vincent.b.1@hotmail.fr
> CC: emacs-devel@gnu.org
> Subject: Re: SES local variables to define printers
> Date: Thu, 30 May 2013 09:20:13 -0400
> 
> > Ok you means _after_ the ses-cell declaration, just before those general
> > declarations (taken from examples.ses):
> 
> For example. I don't think it matters much whether they come after or
> before the ses-cell calls.
> 

I think it does if ses counts lines to access the ses-cell rows --- TBC.


[...]

> 
> Elisp doesn't have buffer-local functions, indeed.
> 

OK, good to know...


[...]

> 
> Actually, you don't need to use the symbol at all.

I need the symbol, because for instance if the symbol is ses-dashfill or
math-format-value, then I would directly call the corresponding
symbol-function rather than indexing the hash map.

So I need some trick to know whether the symbol is a function name or a
printer function. One simple trick would be to set the symbol value slot
to some fixed value, e.g. to symbol :ses-printer. Another way would be
to try the hash-map first and then check whether it is a function as a
fallback, or the other way round. I could also set some property to the
symbol...

My preference would be to set the symbol value to some specific
indicator, I feel that the execution time would be faster this way. 

But maybe I should not care too much about this: one could improve speed
by caching all printer functions directly in the cell object for faster
access, and keeping printer definitions in a cell property.

> In ses-cell, just check if the printer's name is found in your hash-map
> and if so, use the function you found there instead.
> 
> This way, the user can give local names without having to worry about
> affecting other packages which might accidentally be using the
> same names.
> 
> 
> Stefan

BR,
   Vincent.



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

* Re: SES local variables to define printers
  2013-05-30 15:36 Vincent Belaïche
@ 2013-05-30 17:15 ` Stefan Monnier
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Monnier @ 2013-05-30 17:15 UTC (permalink / raw)
  To: Vincent Belaïche; +Cc: emacs-devel

> I need the symbol, because for instance if the symbol is ses-dashfill or
> math-format-value, then I would directly call the corresponding
> symbol-function rather than indexing the hash map.

In ses-cell, you look up the map.  If the name is found, then it's
deemed a reference to a local function, regardless of whether it also
exists as a normal function.  If it isn't found, then it's deemed
a reference to a global function.

Of course, this presumes that the map is setup before we process the
ses-cell calls.

> So I need some trick to know whether the symbol is a function name or a
> printer function.

The trick is to lookup the local printer map.


        Stefan



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

end of thread, other threads:[~2013-05-30 17:15 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-25 20:43 SES local variables to define printers Vincent Belaïche
2013-05-26  1:17 ` Stefan Monnier
  -- strict thread matches above, loose matches on Subject: below --
2013-05-30 15:36 Vincent Belaïche
2013-05-30 17:15 ` Stefan Monnier
2013-05-30  7:24 Vincent Belaïche
2013-05-30  5:50 Vincent Belaïche
2013-05-30 13:20 ` Stefan Monnier
2013-05-28  4:38 Vincent Belaïche
2013-05-28  4:57 ` Stefan Monnier
2013-05-26 20:25 Vincent Belaïche
2013-05-27  1:35 ` Stefan Monnier
2013-05-26  7:16 Vincent Belaïche
2013-05-26 18:02 ` Stefan Monnier
2013-05-24  5:53 Vincent Belaïche
2013-05-24  5:46 Vincent Belaïche
2013-05-24  5:45 Vincent Belaïche
2013-05-24 13:28 ` Stefan Monnier
2013-05-23 20:52 Vincent Belaïche
2013-05-23 21:35 ` Davis Herring
2013-05-24  1:06 ` Glenn Morris

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).