TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Lupo76 on October 08, 2015, 03:17:12 AM

Title: Error Handling
Post by: Lupo76 on October 08, 2015, 03:17:12 AM
Hello to all,
for many years I use the following code for error handling.

Code: [Select]
(defun c:test (/ var msgg)
  ;*************************************
  (setq var (getvar "CMDECHO"))
  (setvar "CMDECHO" 0)
  (setq old-error *error*)
  (defun *error* (msg)
     (setq msgg (strcat "Error!!: " msg))
     (princ msgg)
     (setq *error* old-error)
     (command "_.undo" "_end" "_u")
     (exit)
  )
  (command "_.undo" "_be")
 
  (setq var_OSMODE (getvar "OSMODE"))
  (setvar "OSMODE" 1)
  ;*************************************
 
  (while (= 1 1)
    (command "_.line" "0,0,0" "10,10,0" "")
  )
 
  ;*************************************
  (setvar "OSMODE" var_OSMODE)
  (setq *error* old-error)
  (command "_.undo" "_end")
  (setvar "cmdecho" var)
  (princ)
)


This code should restore the situation of the original design before the work lisp.

It has worked for 15 years, or at least I was convinced of this; today does not work :-(

Today, in AutoCAD 2011, if I press ESC, the while loop is interrupted, and design are all generated before pressing the ESC key. :x
Instead I wish that these lines were automatically removed.
Can you help me understand this?

Also in AutoCAD2016 it goes in error because of the (command).
AutoCAD 2016 wants the (command-s) ... :-o

What is the difference between (command) and (command-s) ??

Title: Re: Error Handling
Post by: ronjonp on October 08, 2015, 08:31:09 AM
I'd suggest removing command calls & creating functions using vla-startundomark & vla-endundomark. Also store your lines in a list then you can delete them in the error handler.
Code - Auto/Visual Lisp: [Select]
  1. (defun c:foo (/ *error* p1 p2 tmp)
  2.   (defun *error* (msg)
  3.     ;; Delete lines
  4.     (and tmp (mapcar 'entdel tmp))
  5.     (if   (not (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*"))
  6.       (princ (strcat "\nError: " msg))
  7.     )
  8.     (princ)
  9.   )
  10.   (while (and (setq p1 (getpoint "\nSpecify first point: "))
  11.          (setq p2 (getpoint p1 "\nSpecify next point: "))
  12.     )
  13.     (setq tmp (cons (entmakex (list '(0 . "LINE") (cons 8 "FOO") (cons 10 p1) (cons 11 p2))) tmp))
  14.   )
  15.   (princ)
  16. )
Title: Re: Error Handling
Post by: Lupo76 on October 08, 2015, 09:20:42 AM
I'd suggest removing command calls & creating functions using vla-startundomark & vla-endundomark. Also store your lines in a list then you can delete them in the error handler.

Hello,
Thank you for your answer.
I tried your code and it works well.
Then I tried to change the part that draws the lines:
Code: [Select]
(defun c:foo (/ p1 p2 tmp)
  ;*************************************
  (defun *error* (msg)
    ;; Delete lines
    (and tmp (mapcar 'entdel tmp))
    (if   (not (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*"))
      (princ (strcat "\nError: " msg))
    )
    (princ)
  )
  ;*************************************
  (while (= 1 1)
    (command "_.line" "0,0,0" "10,10,0" "")
  )
  ;*************************************
  (princ)
)

With your code if I press ESC cancels all, while with my code if I press ESC lines remain  :cry:
Do you have any idea?
Title: Re: Error Handling
Post by: ronjonp on October 08, 2015, 09:40:13 AM
You're not storing the line in a list (tmp) to delete them. How would the error handler know what to delete?
Title: Re: Error Handling
Post by: Lupo76 on October 08, 2015, 09:49:50 AM
You're not storing the line in a list (tmp) to delete them. How would the error handler know what to delete?

In your modified code I do not know.
But in my code of the firt post, should remove all operations performed after (command "_.undo" "_be")

My code has always worked ... but in this example / context has some problems.

Note that this is an example, I have to use this error handling on a lisp much more complex that not only makes the lines.
Title: Re: Error Handling
Post by: ChrisCarlson on October 08, 2015, 01:08:39 PM
I'm a little confused on the (= 1 1) 1 will always = 1.

Why not use (while t (command "_.line" "0,0,0" "10,10,0" "")) if your intent is an endless loop exitable only with escape.
Title: Re: Error Handling
Post by: Lupo76 on October 08, 2015, 01:30:14 PM
I'm a little confused on the (= 1 1) 1 will always = 1.

Why not use (while t (command "_.line" "0,0,0" "10,10,0" "")) if your intent is an endless loop exitable only with escape.

You are right!
but the problem remains :-(
Title: Re: Error Handling
Post by: Kerry on October 08, 2015, 02:08:54 PM

Lupo76,

One of the important things about Ron's code is that the *error* function is declared local to the main routine, and does not use the setting and getting of old-error

I noticed that you ignored that.

Title: Re: Error Handling
Post by: Lupo76 on October 09, 2015, 06:38:01 AM

Lupo76,

One of the important things about Ron's code is that the *error* function is declared local to the main routine, and does not use the setting and getting of old-error

I noticed that you ignored that.

Ok this is true.
But Ron's code simply deletes the lines stored in the "tmp" list.

A lisp function can be very complex and do many things (drawing objects, turn off and on layers, change dimension styles or text, etc. Etc.).
It can happen, in some conditions not provided, that the function goes wrong prematurely, or the user presses ESC to cancel it.

With my initial code when this occurs all is canceled.
With Ron's code I have to be attentive to every possible variation to the design caused by the function during its production and cancel it when crash: this involves too much work.

I'm looking for a code that I can use anywhere, any lisp function or in most of them, so that I can concentrate only on the solution of errors for user input (initget, etc.).
Title: Re: Error Handling
Post by: Kerry on October 09, 2015, 09:00:44 AM
Perhaps have a look at doing something like this :

Code - Auto/Visual Lisp: [Select]
  1.  ;; add this to a library file that is loaded into drawing by default.
  2.  
  3. (defun myDefault*error* (msg)
  4.   (while (< 0 (getvar 'cmdactive)) (command-s nil))
  5.   (setvar 'menuecho 1)
  6.   (cond ((not msg))
  7.         ((member (strcase msg t)
  8.                  '("console break" "function cancelled" "quit / exit abort")
  9.          )
  10.          (princ "\nFunction Cancelled.")
  11.         )
  12.         ((princ (strcat "\nApplication Error: " (itoa (getvar 'errno)) " :- " msg))
  13.          (vl-bt)
  14.         )
  15.   )
  16.   (setvar 'errno 0)
  17.   (princ)
  18. )
  19.  
Code - Auto/Visual Lisp: [Select]
  1. (defun c:doit (/ *error* otherLocalFunctionsAndVariables)
  2.  
  3.   (defun *error* (msg)
  4.     (myDefault*error* msg)
  5.     ;;
  6.     ;; add other application specific error fixup stuff here :-
  7.   )
  8.   ;; main content follows ...
  9.  
  10.  
  11.   ;; restore changed vars and default cleanup ;; <= added 20170219
  12.   (*error* nil)
  13.   (princ)
  14. )
  15.  
  16.  
Title: Re: Error Handling
Post by: JohnK on October 09, 2015, 12:01:12 PM
At one time I tried to set up an overall error handler which you can find here:
https://www.theswamp.org/index.php?topic=13730.msg165767#msg165767

Please note the lesson Kerry is trying to teach you about localizing your error handler though. If you attempt to use mine, please understand/accept/revise the example I used in the above link (the example I linked to is set to be global). Please try to understand and choose the best method for you (I made no mention of global/local in my above link and left the decision up to anyone that wanted to use it).
Title: Re: Error Handling
Post by: dgorsman on October 09, 2015, 12:27:44 PM
This is where establishing standard coding practices come in.  You should be striving to handle the same or similar things the same way, which allows for a global error handler to take on most of the common problems.

There will always be exceptions to this (although they should be minimal) and the error handler can always be replaced for the required scope.  Because the error handler can be composed of calls to other functions, and functions can be redefined on-the-fly, individual functions or the entire error handler can be overwritten to manage custom error handling requirements, although in all cases (both error and non-error states) should restore the system back to the known/global configuration.
Title: Re: Error Handling
Post by: kdub_nz on February 19, 2017, 12:27:19 AM

Added clarification regarding function finalisation.
(p.msg request )
Code - Auto/Visual Lisp: [Select]
  1.   ;; restore changed vars and default cleanup ;; <= added 20170219
  2.   (*error* nil)
  3.   (princ)
  4.