Author Topic: Share your ERROR subroutine to get best one  (Read 10463 times)

0 Members and 1 Guest are viewing this topic.

HasanCAD

  • Swamp Rat
  • Posts: 1421
Share your ERROR subroutine to get best one
« on: July 04, 2010, 04:42:48 AM »
Hi all

Lets share ERROR subroutine to get best one

mine is (I copied from a lisp)

Code: [Select]
  (defun *error* (msg)
    (and uFlag (vla-EndUndoMark doc))
    (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
        (princ (strcat "\n** Error: " msg " **")))
    (princ))

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Share your ERROR subroutine to get best one
« Reply #1 on: July 04, 2010, 05:17:37 AM »
Hi,

IMO there's no 'best error subroutine'.
The error subroutine may be different for each main routine according to what you may have to reset:
- ending undo mark (no need to test uFlag with vla-EndUndoMark)
- restoring sysvar values
- closing an opened file
- erasing a temporary entity
- etc.
Speaking English as a French Frog

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Share your ERROR subroutine to get best one
« Reply #2 on: July 04, 2010, 09:42:41 AM »
I agree with gile. Here is MY basic error handler.
Code: [Select]
  (defun *error* (msg)
    (if (and msg (/= msg "") (not (wcmatch (strcase msg) "*QUIT*,*CANCEL*")))
       (princ (strcat "\nError: " msg))
    )
    (and usercmd (setvar "CMDECHO" usercmd))
    (and useros (setvar "osmode" useros))
    (princ)
  ) ; end error function
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

efernal

  • Bull Frog
  • Posts: 206
Re: Share your ERROR subroutine to get best one
« Reply #3 on: July 04, 2010, 10:08:37 AM »
;; I use something like this:

Code: [Select]
(defun ef_my_error (s)
  (if ef_undo
    (progn (command "_.undo" "end") (command "_.u"))
  )
  (setq ef_undo nil)
  (if ef_lista_vars
    (foreach x ef_lista_vars (setvar (car x) (cadr x)))
  )
  (if (and opened_file (= (type opened_file) 'file))
    (close opened_file)
  )
  (if ef_old_error
    (setq *error* ef_old_error)
  )
  (princ "\n-> Erro : ")
  (princ s)
  (princ)
)

efernal


<edit: code tags added. >
« Last Edit: July 04, 2010, 11:41:42 AM by CAB »
e.fernal

Crank

  • Water Moccasin
  • Posts: 1503
Re: Share your ERROR subroutine to get best one
« Reply #4 on: July 04, 2010, 02:17:08 PM »
Another:
Code: [Select]
(defun c:DEMO ( / *error* *finish* Gb-varlist Gb-temperr)
(setq Gb-varList '("OSMODE" "DYNMODE" "BLIPMODE"); EXAMPLE OF THE VARIABLES YOU WANT TO RESTORE
      Gb-varList (mapcar (function (lambda (a) (list 'setvar a (getvar a)))) Gb-varList)
      Gb-temperr *error*)
(defun *finish* ()
(mapcar 'eval Gb-varList)(setq *error* Gb-temperr)(command "_.undo" "_end")
)
(defun *error* (msg)
(prompt (strcat "\nError: " msg))
(*finish*)
(command "_.u")
(princ)
)
(command "_.undo" "_be")

; Do your stuff

(*finish*)
(princ)
)
Vault Professional 2023     +     AEC Collection

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: Share your ERROR subroutine to get best one
« Reply #6 on: July 04, 2010, 07:05:38 PM »
Code: [Select]
(defun *error* (msg)
  (if (and msg (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*QUIT*,")))
    (princ (strcat "\nError: " msg))
  )
)
It basically does the same thing as Alan's, just with a little less legwork (notice the extra comma on the end).
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

Hangman

  • Swamp Rat
  • Posts: 566
Re: Share your ERROR subroutine to get best one
« Reply #7 on: July 06, 2010, 12:05:17 PM »
Here is my error handling bungle.
Code: [Select]
  (defun *error* (msg /)
    (template:on-error msg)
    (princ)
  )

I borrowed this following piece from one of Kerry's posts, I like the way he put it together.
Code: [Select]
;; Error control  Thanks to Kerry - theSwamp
(pragma '((unprotect-assign template:on-error)))
;;
(defun template:on-error (msg / tmp)
;;----- Cancel any Active Commands -----------------------------
  (while
    (> (getvar "cmdactive") 0)
    (command)
  )
  (setvar "menuecho" 1)
  (command ".undo" "End" ".undo" "Back")
[color=green]; I've learned to only use the ".undo" command on lengthy routines where several things occur, and then with caution.[/color]
;;----- Display error message if applicable _-------------------
  (cond ((not msg))                          ; no error, do nothing
        ((member
           (strcase msg t)                   ; cancel
           '("console break" "function cancelled" "quit / exit abort")
         )
         (princ "\n\tFunction Cancelled\n\tFunction Cancelled")
        )
        ((princ (strcat "\nApplication Error: "
                        (itoa (getvar "errno"))
                        " :- "
                        msg "\n"
                )
         )
        )
  )
  ;;----- Reset System Variables ----------------
  (setvar "osmode" origOS)
  (setvar "autosnap" origASN)
  (setvar "menuecho" 0)
  (setvar "cmdecho" 1)
  (command ".redraw")
  (setq *error* nil)
  (princ)
)
;;
(pragma '((protect-assign template:on-error)))
;;

I've been slowly learning more and more about the functionality of error handling, and the more I learn, the more I learn there is so much more to learn than what I initially determined.
And I have recently discovered, as Gile pointed out:
Hi,

IMO there's no 'best error subroutine'.
The error subroutine may be different for each main routine according to what you may have to reset:
- ending undo mark (no need to test uFlag with vla-EndUndoMark)
- restoring sysvar values
- closing an opened file
- erasing a temporary entity
- etc.

And I am now wondering if it is worth having several small error handling cases in a large LiSP routine, each focusing on a particular issue, rather than one final error handling routine to cover any and all there is in the LiSP routine?.
Hangman  8)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Drafting Board, Mechanical Arm, KOH-I-NOOR 0.7mm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Share your ERROR subroutine to get best one
« Reply #8 on: July 07, 2010, 05:59:59 AM »
I won't devote too much time or space to this 'cause there's a football match I want to watch shortly tonight.

Error trapping is a mechanism thats is quite often disregarded and frequently mis-understood.

The primary function of error trapping is twofold,
to attempt to advise the user when an error occurs
to attempt to restore the system to a state similar to it's previous condition

The level of trapping and handling will depend on the type of routines the programmer is developing.

I usually break the coding of error handlers into 2 phases.

Firstly I have a standard template and handler framework kept in my library,
then I add specific functionality to suit the type of routine being developed.

do we need to consider open file handles ;
have we any ActiveX objects that need to be released ;
will we write data to a log file ;
does the user deserve a slap on the wrist for the error ;
etc

Here's my core functions :
A function for saving the environment state prior to running a routine
A function for handling any error message itself.
A function for restoring the presaved environment.

Code: [Select]

;;------------------------------------------------------------------
;;;------------------------------------------------------------------
;;;
(vl-load-com)
(or kglobal:acadapp (setq kglobal:acadapp (vlax-get-acad-object)))
(or kglobal:activedoc
    (setq kglobal:activedoc (vla-get-activedocument kglobal:acadapp))
)
;;;-----------------------------------------------------------------------
;;;
(defun kdub:on-error (msg / tmp)
  ;;----- Cancel any Active Commands -------------------------------------
  (while (< 0 (getvar "cmdactive")) (command))
  (setvar "menuecho" 1)
  (vla-endundomark kglobal:activedoc)
  ;;----- Display error message if applicable _---------------------------
  (cond
    ((not msg))                              ; no error, so do nothing
    ((member (strcase msg t)                 ; if cancel or quit
             '("console break" "function cancelled" "quit / exit abort")
     )
    )
    ((princ (strcat "\nApplication Error: " (itoa (getvar "errno")) " :- " msg))
     ;;----- Display backtrace ------------------------------------------
     (vl-bt)
    )
  )
  (setvar "errno" 0)
  ;;----- Release Bound Special Activex Objects --------------------------
  (foreach varname kglobal:objectsbound
    (if (= (type (setq tmp (vl-symbol-value varname))) 'vla-object)
      (if (not (vlax-object-released-p tmp))
        (vlax-release-object tmp)
      )
    )
    (set varname nil)
  )
  ;;----- Reset System Variables from global list ------------------------
  (foreach item kglobal:sysvarlist (setvar (car item) (cadr item)))
  ;;
  (setq kglobal:sysvarlist nil
        kglobal:objectsbound nil
  )
  (princ)
)




Code: [Select]
;;;-----------------------------------------------------------------------
;;; change sysvar value and save its previous value
  
(defun kdub:savesysvar (vars_list)
  ;; Save the values of these vars in case they are changed in the calling routine
   ;;    they will be saved with the vars listed in  vars_list
   ;; Note that some will be preset to ensure they meet the default values we require
   ;; If we want to override these simply add the items into the calling parameters
   ;;    in the calling routine
  (setq generalVars
            '(("CMDECHO"  0) ; save current and Turns off echoing
             ("expert"    ) ; save current value
             ("ORTHOMODE" ) ; save current value
             ("SNAPANG"   ) ; save current value
             ("UCSICON"   ) ; save current value
             ("SNAPMODE"  ) ; save current value
             ("OSMODE"    ) ; save current value
             ("PICKADD"  2) ; save current and  Turns on PICKADD. Shift-Pick to remove
             ("PICKAUTO" 1) ; save current and  Draws a selection window (for either a window or a crossing selection) automatically
             ("PICKBOX"  5) ; save current and  initial is 3. my default is 6
             ("INSUNITS" 0) ; save current and  Unspecified (No units)
             ("SORTENTS" 1) ; save current and  use selection Order to control
            )
   )  
  (foreach item  (append  vars_list generalVars)
    (setq kglobal:sysvarlist (cons (list (car item) (getvar (car item)))
                                   kglobal:sysvarlist
                             )
    )
    (if (cadr item)
      (setvar (car item) (eval (cadr item)))
    )
  )
)


Code: [Select]

;;;-----------------------------------------------------------------------
;;; ( kdub:restoresysvar )
(defun kdub:restoresysvar ()
  (foreach item kglobal:sysvarlist (setvar (car item) (cadr item)))
  (setq kglobal:sysvarlist nil)
  (princ)
)

These functions are loaded into each session in a VLX along with other library functions.

Then when writing routines it's simply a matter of calling those functions

Note that the *error* routine is declared LOCAL to the routine.

for example :

Code: [Select]

(vl-load-com)
(or kglobal:acadapp (setq kglobal:acadapp (vlax-get-acad-object)))
(or kglobal:activedoc
    (setq kglobal:activedoc (vla-get-activedocument kglobal:acadapp))
)

(defun c:DoItAgainSam ( / *error*
                      ;;
                      local vars go here
                      fileName fh escape result
                      )
  ;;-----------------------------------------------------------
  (defun *error* (msg)
    (kdub:on-error msg)
    ;;
    (vl-cmdf "_.UCS" "_Restore" prev:ucs)    
    (princ)
  )
  (vla-endundomark kglobal:activedoc)        ;close any open group
  (vla-startundomark kglobal:activedoc)      ;start new group
  ;;-----------------------------------------------------------
  ;; save the current value of these vars and set as noted
  ;; the values will be restored on exit or error.
  (kdub:savesysvar '(("CMDECHO"  0)
                     ("expert"   5)
                     ("PLINEGEN" 1)
                     ("BLIPMODE" 1)
                     ("CLAYER"    ) ; save current value               
                    )
  )
  (setq prev:ucs "TMP_ORIGINAL")
  (vl-cmdf "_.UCS" "_Save" prev:ucs)
  ;;-----------------------------------------------------------
  ;;-----------------------------------------------------------
  ;;

   ;; mojo goes here
  
   ;; comment out these statements to test
  (setq escape (getpoint "either pock a point or hit ESC"))

  (command "_.ucs" "Z" 75)
  ;;
  (command "_.Layer" "_M" "Test" "")

  (setq escape (getpoint "\nEither pick a point or hit ESC"))

  
  (setq fileName "Z:/NoFolderExists/NoFileExists.txt")
  (setq fh (open fileName "w"))

  (print fh "Stuff to add to file.")


  (setq result (/ 12.0 (getreal "\nEnter an number ... zero would be fun")))  
  ;; more mojo goes here

  ;; restore the vars if we get this far
  (kdub:restoresysvar)
  (princ)
)






 
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Re: Share your ERROR subroutine to get best one
« Reply #9 on: July 07, 2010, 08:48:43 AM »
mine is (I copied from a lisp)

Hardly 'yours' since you copied it straight from one of my programs - the UndoMark is not needed in general anyway...

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: Share your ERROR subroutine to get best one
« Reply #10 on: July 07, 2010, 08:50:24 AM »
mine is (I copied from a lisp)

Hardly 'yours' since you copied it straight from one of my programs - the UndoMark is not needed in general anyway...
I think he meant 'mine' as in that's the one he uses.
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Re: Share your ERROR subroutine to get best one
« Reply #11 on: July 07, 2010, 08:55:49 AM »
*shrug*  :|

JohnK

  • Administrator
  • Seagull
  • Posts: 10625
Re: Share your ERROR subroutine to get best one
« Reply #12 on: July 07, 2010, 09:01:20 AM »
mine is (I copied from a lisp)

Hardly 'yours' since you copied it straight from one of my programs - the UndoMark is not needed in general anyway...

At least your stuff gets used; my stuff i cant give away?! I'm like that one guy in town that everybody kinda looks at funny like.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

CHulse

  • Swamp Rat
  • Posts: 504
Re: Share your ERROR subroutine to get best one
« Reply #13 on: July 07, 2010, 09:05:47 AM »
*shrug*  :|

I must admit, I use one of Lee's also - but I take no credit...

Code: [Select]
;; --{  Error Handler Function  }--
;; by Lee Mac ~ 2010

  (defun *error* (msg)     ...

You should be flattered :)

Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

Lee Mac

  • Seagull
  • Posts: 12912
  • London, England
Re: Share your ERROR subroutine to get best one
« Reply #14 on: July 07, 2010, 09:13:52 AM »
You should be flattered :)

Don't get me wrong, I am flattered when I see my code being used by others - but I just get peeved when code is blatently copy/pasted with no credit as to the source is all.