Author Topic: Universal Error Function  (Read 15100 times)

0 Members and 1 Guest are viewing this topic.

GDF

  • Water Moccasin
  • Posts: 2081
Universal Error Function
« on: February 03, 2006, 12:28:40 PM »
Can I modify (redine) AutoCAD's error function and add something to it, so that a cancel or escape will use my redefined error function?

I know I can modeify it within a lisp routine, I am looking for a universal error function for all of my routines.

Does this make sense?

Gary
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

hudster

  • Gator
  • Posts: 2848
Re: Universal Error Function
« Reply #1 on: February 03, 2006, 12:32:52 PM »
Use the one on the afra lisp website and then call it from each routine, that's what I do.

http://www.afralisp.co.za/lispa/lisp6.htm
Revit BDS 2017, 2016, 2015, 2014, AutoCAD 2017, 2016, Navisworks 2017, 2016, BIM360 Glue

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Universal Error Function
« Reply #2 on: February 03, 2006, 01:08:43 PM »
I think all you have to do is redefine the *error* function.  So if you have one that you want, and will work in all instances, the just do that in an mnl file or something that loads with every drawing.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Universal Error Function
« Reply #3 on: February 03, 2006, 01:23:35 PM »

The *error* function should be LOCAL to the routine and declared as such ..

There are a lot of different ways to do it, here's one :

Code: [Select]
(defun c:Test (/ *error*)
  ;;
  ;; ----- set error trap ----------------------------------------
  (defun *error* (msg) (kb:on_error msg) (princ))
  (vla-endundomark kbg_activedoc)                     ;close open group
  (vla-startundomark kbg_activedoc)                   ;start new group
  (kb:savesysvar '(("CMDECHO" 0)
                     ("CLAYER")
                     ("BLIPMODE" 0)
                     ("OSMODE" 0)
                     ("ORTHOMODE" 0)
                     ("SNAPANG" 0.0)
                    )
  )
  ;; ----- initialise --------------------------------------------
  ;; ----- main body  --------------------------------------------
  (*error* nil)
  (princ)
)

with these :
Code: [Select]
;;;-----------------------------------------------------------------------------------
;;;----------------------------------------------------------------------------------- _
;;;       helper Library
;;;-----------------------------------------------------------------------------------
;;;----------------------------------------------------------------------------------- _
;;; change sysvar value and save its previous value

(defun kb:savesysvar (vars_list)
  (foreach item vars_list
    (setq kbg_sysvarlist (cons (list (car item) (getvar (car item))) kbg_sysvarlist))
    (if (cadr item)
      (setvar (car item) (cadr item))
    )
  )
)

;;;-----------------------------------------------------------------------------------
;;;-----------------------------------------------------------------------------------
(defun kb:on_error (msg / tmp)
  ;;----- Cancel any Active Commands -----------------------------
  (while (< 0 (getvar "cmdactive")) (command))
  (setvar "menuecho" 1)
  (vla-endundomark (vla-get-activedocument (vlax-get-acad-object)))
  ;;----- 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
       (strcat "\nApplication Error: " (itoa (getvar "errno")) " :- " msg)
     )
    )
  )
  (setvar "errno" 0)
  ;;----- Display backtrace if in debug mode ---------------------
  (if kbg_debug_on
    (vl-bt)
  )
  ;;----- Release Bound Activex Objects --------------------------
  (foreach varname kbg_objectsbound
    (if (= (type (setq tmp (vl-symbol-value varname))) 'vla-object)
      (if (not (vlax-object-released-p tmp))
(progn (vlax-release-object tmp) (set varname nil))
      )
    )
  )
  ;;----- Reset System Variables from global list ----------------
  (foreach item kbg_sysvarlist (setvar (car item) (cadr item)))
  (setq kbg_sysvarlist nil
kbg_objectsbound nil
  )
  (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.

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #4 on: February 03, 2006, 01:48:38 PM »
Thanks guys, I will play around with the tips over the weekend.

In vanilla AutoCAD where does the *cancel* come from when no lisp routine has been cancelled out?


Command: *Cancel*

Gary
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Universal Error Function
« Reply #5 on: February 03, 2006, 01:50:03 PM »
Thanks guys, I will play around with the tips over the weekend.

In vanilla AutoCAD where does the *cancel* come from when no lisp routine has been cancelled out?


Command: *Cancel*

Gary

Most likely it is written in the code for the default error routine. </guess>
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #6 on: February 03, 2006, 02:01:34 PM »
I think you are correct. However what I would like to do is have one universal error function for all routines that would override any existing error function,
like what one would do with the following ex: (setq S::Startup (append S::Startup ARCH::STARUP))

It would be neat if you could append, redefine or what ever and have the global-universar error function work for everthing. As part of this error funtion it would reset
all vars.

Here is what I use for each routine, error trapped within each routine.

Code: [Select]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Undo Mark Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ARCH:UBEG  ()
  (setvar "CMDECHO" 0)
  (setq UNDO_BEGIN T)
  (command "UNDO" "BEGIN")
  (setvar "CMDECHO" 1)
  (princ))
(defun ARCH:UEND  ()
  (setvar "CMDECHO" 0)
  (setq UNDO_BEGIN ())
  (command "UNDO" "END")
  (setvar "CMDECHO" 1)
  (princ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Error Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ARCH:ERROR  (Msg)
  (setvar "cmdecho" 0)
  ;;(command "_ucs" "");dont use
  (setvar "cmdecho" 1)
  (if (and Msg (not (eq Msg "quit / exit abort")))
    ;;(princ Msg)
    (princ "\n\n*** ///////// Program  CANCELLED ///////// ***\n"))
  (ARCH:F_R-VAR)
  (princ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Error Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ARCH:ERROR  (Msg)
  (setvar "cmdecho" 0)
  ;;(command "_ucs" "");dont use
  (setvar "cmdecho" 1)
  (if (and Msg (not (eq Msg "quit / exit abort")))
    ;;(princ Msg)
    (princ "\n\n*** ///////// Program  CANCELLED ///////// ***\n"))
  (ARCH:F_R-VAR)
  (princ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Clean Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Juerg Menzi
;;;MENZI ENGINEERING GmbH, Switzerland
;;;http://www.menziengineering.ch
(defun ARCH:F_CLEAN  (Lst)
  (or Me:Aco (setq Me:Aco (vlax-get-acad-object)))
  (or Me:Acd (setq Me:Acd (vla-get-ActiveDocument Me:Aco)))
  (vla-StartUndoMark Me:Acd)
  (setq Me:Oer  *Error*
        *Error* ARCH:ERROR)
  (mapcar '(lambda (l)
             (if (not (assoc l Me:Var))
               (setq Me:Var (append Me:Var (list (cons l (getvar l)))))))
          Lst)
  (princ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; F_S-VAR Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ARCH:F_S-VAR  ()
  (ARCH:F_CLEAN
    '("APERTURE" "ATTDIA" "ATTREQ" "BLIPMODE" "CECOLOR" "CLAYER" "CELTYPE" "CMDECHO"
      "DIMSCALE" "DRAGMODE" "EXPERT" "FILEDIA" "FILLETRAD" "GRIDMODE" "HIGHLIGHT" "LUNITS"
      "MENUECHO" "MIRRTEXT" "OFFSETDIST" "ORTHOMODE" "OSMODE" "PICKBOX" "PLINEWID" "REGENMODE"
      "SNAPMODE" "SNAPUNIT" "SNAPBASE" "SNAPANG" "SNAPSTYL" "TEXTEVAL" "TEXTSTYLE")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; F_R-VAR Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Juerg Menzi
;;;MENZI ENGINEERING GmbH, Switzerland
;;;http://www.menziengineering.ch
(defun ARCH:F_R-VAR  ()
  (if Me:Var
    (mapcar '(lambda (l) (setvar (car l) (cdr l))) Me:Var))
  (setq *Error* Me:Oer
        Me:Oer  nil
        Me:Var  nil)
  (vla-EndUndoMark Me:Acd)
  (princ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;; Check Global Variables Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;10/13/99 Bill Zondlo
;;;use this program to clean up your custom autolisp programs.
;;;quickly finds user global variables/functions defined during use of custom programs,
;;;so you can add them to your local variables list without searching each line of program.
;;;It displays a list of new variables set during the drawing session.
;;;(setq ARCH#CHKV (atoms-family 1)) ;add to s::startup to make list
(defun ARCH:ChkGlobalVals  (/ ltr ltt)
;;;after custom program is run, run this program.
  (setq ltt (atoms-family 1))
;;;to get list of newly defined variables/functions.
  (princ (strcat "\nARCH#CHKV > "
                 (rtos (length ARCH#CHKV) 2 0)
                 " - ltt > "
                 (rtos (length ltt) 2 0))) ;prints length of each list.
  (foreach
         n  ltt ;compares each item in new list.
    (if (not (member n ARCH#CHKV))
    ;of newly defined variables/functions since start of drawing.     
      (setq ltr (append ltr (list n))) ;makes list of new items.
      ) ;end if
    (ARCH:WORKING)) ;end foreach
  (if (not (null ltr)) ;if new items.
    (progn (textscr) ;flips to text screen.
           (foreach m ltr (princ (strcat "\n " m))) ;prints new items to screen.
           ) ;end progn
    ) ;end if
  (princ)) ;end defun

Gary (in the dark)
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Universal Error Function
« Reply #7 on: February 03, 2006, 02:28:33 PM »
The problem I see about trying to have one error function for all routines is you would have to name all your variables the same in all.  If you use objectdbx, or access to other programs that have to be release in certain ways, then that would be hard.  Maybe you can have one main one that would work with simple routines, and then one per more involved routines.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #8 on: February 03, 2006, 02:42:04 PM »
Thanks, I just realized that I don't know what I'm talking about, so I'll just keep things the way they are.

(the lights have been turned off)
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

CADmium

  • Newt
  • Posts: 33
Re: Universal Error Function
« Reply #9 on: February 04, 2006, 03:02:00 PM »
We also had discussed this theme... here ist the result
"Bei 99% aller Probleme ist die umfassende Beschreibung des Problems bereits mehr als die Hälfte der Lösung desselben."

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #10 on: February 06, 2006, 10:01:39 AM »
Thanks

Code: [Select]
We also had discussed this theme... here ist the result

But I don't speak anything but Texan
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

CADmium

  • Newt
  • Posts: 33
Re: Universal Error Function
« Reply #11 on: February 06, 2006, 10:36:15 AM »
But I don't speak anything but Texan

<dream> i know , that's german ( my english is also not so good). But the code is international, or not?
P.S: Google has also a translater

Thomas
"Bei 99% aller Probleme ist die umfassende Beschreibung des Problems bereits mehr als die Hälfte der Lösung desselben."

t-bear

  • Guest
Re: Universal Error Function
« Reply #12 on: February 06, 2006, 01:52:26 PM »
Thomas...your English is light-years ahead of my German.  :roll:
I like your sig..."In 99% of all problems, the comprehensive description of the problem is more than the half of the solution ." 

(Google translation, as you recommended)................. :angel:

If I get the time today, I'll attempt a translation of the code.............wish me luck!

t-bear

  • Guest
Re: Universal Error Function
« Reply #13 on: February 07, 2006, 08:11:39 AM »
here's what I came up with...it will need cleaning up.
Code: [Select]
Code:
    ;|
    Global Errorhandler
    Inklusive Undo-Funktion
    Inklusive Huckepack-Funktions Unterstützung
    - Beim Start
    - Bei Durchlauf ohne Fehler
    - Im Fehlerfall

    February 2004
    In collaboration with various CAD. DE Membern emerged

   More special thanks to at MAPCAR (http://www.autolisp.mapcar.net) for the        basis-Error-Handler and all the nice information on the nice Lisp-Interna :-).

    StartErrorHandler : Pile bar error correction routine arguments:
    NAME      = Freely more eligible String.
    If a (*error*)-Function issues something on the screen, it sets this name in addition so that one can recognize, what comes of which instance of the Errhandlers. 

    UNDOMODE     = T or Nil can be.
    Indicates whether in the mistake case and/or discontinuance case immediately the command is supposed to be
carried out 'UNDO', around all until there undertaken to make actions immediately annulled. 

    VARS_TO_SAVE = list of the system to be set and global variable

    ON-START     = Function that in the start carried out becomes (Nile for "do nothing carry out")
    ON-GOOD      = Function that in flawless conduit carried out becomes (Nil for "do nothing carry out")

    ON-BAD       = Function that in the mistake case carried out becomes (Nil for "do nothing carry out")

    ***********************************************************
    * Debugging /Activate back messages of the Errorhandlers: *
    * Setting of the GLOBAL variables (setq *VERBOSE* T)        *
    ***********************************************************

    Example 1: setting / Rücksetzen of Sysvars
    -------------------------------------------
    (defun C:TEST (/)
      (STARTERRORHANDLER
        "Function TEST"
        't
        '(("cmdecho" . 0) ("filedia" . 0))
        nil
        nil
        nil
      ) ;_ end of startErrorHandler
     
      (machwas)
     
      (ENDERRORHANDLER) ;_ NAME sets the variables out of the argument again back);_ of defun end

    Examples 2: use of user-defined of variable
    -----------------------------------------------------
    (defun C:LV-TEST (/)
      (STARTERRORHANDLER
        "LV-Test"
        't
        NIL
        '(lambda (/)
           (if (= INSTANCE 1)
             (SAVE-VARS '(MYVAR1 MYVAR2 MYVAR3) '*MYVARSTACK*)
           ) ;_ end of if
         ) ;_ end of lambda
        NIL
        '(lambda (/)
           (if (= INSTANCE 1)
             (RESTORE-VARS '*MYVARSTACK*)
           ) ;_ end of if
         ) ;_ end of lambda
      ) ;_ end of startErrorHandler
      (setq MYVAR1 4
            MYVAR2 5
            MYVAR3 6
      ) ;_ end of setq
      (getint "\nIrgendeine number input or ESC for discontinuance: ")
      (ENDERRORHANDLER)
    ) ;_ end of defun

    Examples 3: setting of the WKS / Rücksetzen of the BKS
    -----------------------------------------------------
    (defun C:WKSTEST (/)
      (STARTERRORHANDLER
        "WKSTest"
        't
        '(
          ("CMDECHO" . 0)
          ("CMDDIA" . 0)
          ("FILEDIA" . 0)
         )
        'SAVE-UCS                           ; on-start
        'RESTORE-UCS                        ; on-good
        NIL                                 ; Undo Also the BKS puts back! 
      ) ;_ end of startErrorHandler
      (getint "\input nIrgendeine number or ESC for discontinuance: ")
      (ENDERRORHANDLER)
    ) ;_ end of defun

    |;
    (defun STARTERRORHANDLER (NAME         UNDOMODE     VARSTOSAVE
                              ON-START     ON-GOOD      ON-BAD
                              /            ERRORTEMPLATE
                              SAVELIST     INSTANCE     O_CMDECHO
                             )
      (setq ERRORTEMPLATE
             '((MSG         /           NAME        UNDO        SAVEDVARS
                PREVIOUSHANDLER         INSTANCE    ON-START    ON-GOOD
                ON-BAD
               )
               ;;... Line yet is used  ;(setq instance <> )
               ;;... Line yet is used  ;(setq undo [T|nil])
               ;;... Line yet is used  ;(setq previoushandler <> )
               ;;... Line yet is used  ;(setq name <> )
               ;;... Line yet is used  ;(setq savedvars (quote ...
               ;;... Line yet is used  ;(setq on-start...
               ;;... Line yet is used  ;(setq on-good...
               ;;... Line yet is used  ;(setq on-bad...
               (while (> (getvar "cmdactive") 0) (command))
               (if
                (= INSTANCE 1)
                (progn
                 (command "_undo" "_end")
                 (if
                  (and UNDO MSG)
                  (command "_u")
                 )
                )
               )
               (foreach
                PAIR
                SAVEDVARS
                (setvar (car PAIR) (cdr PAIR))
                (if
                 (and MSG *VERBOSE*)
                 (progn
                  (princ
                   (strcat
                    "\n"
                    NAME
                    "("
                    (itoa INSTANCE)
                    "): Setze \""
                    (car PAIR)
                    "\" back up "
                   )
                  )
                  (princ (cdr PAIR))
                 )
                )
               )
               (if
                MSG
                (progn
                 (if
                  (and (= INSTANCE 1) *VERBOSE*)
                  (princ
                   (strcat "\nError:" NAME "(" (itoa INSTANCE) "): \"" MSG "\"")
                  )
                 )
                 (if
                  ON-BAD
                  ((eval ON-BAD))
                 )
                )
                (if
                 ON-GOOD
                 ((eval ON-GOOD))
                )
               )
               (setq *ERROR* PREVIOUSHANDLER)
               (if
                (= INSTANCE 1)
                (princ)
                (*ERROR* MSG)
               )
              )
      ) ;_ end of setq

      ;;*****************************************************

      (setq INSTANCE
             (if (or (= (type *ERROR*) 'SUBR) (null *ERROR*))
               1
               (1+ (caddr (cadr *ERROR*)))
             ) ;_ end of if
      ) ;_ end of setq
      (if (= INSTANCE 1)
        (progn
          (setq O_CMDECHO (getvar "cmdecho"))
          (setvar "cmdecho" 0)
          (command "_undo" "_begin")
          (setvar "cmdecho" O_CMDECHO)
        ) ;_ end of progn
      ) ;_ end of if
      (foreach PAIR VARSTOSAVE
        (setq SAVELIST
               (cons
                 (cons (car PAIR) (getvar (car PAIR)))
                 SAVELIST
               ) ;_ end of cons
        ) ;_ end of setq
        (setvar (car PAIR) (cdr PAIR))
      ) ;_ end of foreach
      (if ON-START
        ((eval ON-START))
      ) ;_ end of if
      (setq *ERROR*
             (append
               (list (car ERRORTEMPLATE))
               (list (list 'setq 'INSTANCE INSTANCE))
               (if UNDOMODE
                 '((setq UNDO 't))
                 '((setq UNDO NIL))
               ) ;_ end of if
               (list
                 (list 'setq
                       'PREVIOUSHANDLER
                       (cons 'quote (list *ERROR*))
                 ) ;_ end of list
               ) ;_ end of list
               (list (list 'setq 'NAME NAME))
               (list
                 (cons 'setq
                       (cons 'SAVEDVARS
                             (list (cons 'quote (list SAVELIST)))
                       ) ;_ end of cons
                 ) ;_ end of cons
               ) ;_ end of list
               (list (list 'setq 'ON-START ON-START))
               (list (list 'setq 'ON-GOOD ON-GOOD))
               (list (list 'setq 'ON-BAD ON-BAD))
               (cdr ERRORTEMPLATE)
             ) ;_ end of append
      ) ;_ end of setq
      (princ)
    ) ;_ end of defun

    ;|
    Put back global Errorhandler and restore Sysvars.

    More special thanks to at MAPCAR (http://www.autolisp.mapcar.net) for its Error-Handler
    endErrorHandler : Errorhandler put back and restore Sysvars
    Argument:
    No

    Example:
    Simply at the end of the routine

    (ENDERRORHANDLER)

   Call. 

    |;
    (defun ENDERRORHANDLER (/)
      (*ERROR* NIL)
    ) ;_ end of defun

    ;;; Sub-Functions For possible Huckepack-functions of the Errorhandler.

   ;;; Function determines whether the world coordinate system is current
   ;;; at present the proclamation.
   ;;; If not, is set it and T returned
   ;;; if yes the function gives Nil back

    (defun WORLD-UCS (/)
      (if (= (getvar "worlducs") 0)
        (progn (command "_.ucs" "_w") 't)
      ) ;_ end of if
    ) ;_ end of defun

    ;;; Function prior produces BKS again if UCSFLAG T is
    (defun PREVIOUS-UCS (/)
      (if UCSFLAG
        (command "_.ucs" "_p")
      ) ;_ end of if
    ) ;_ end of defun

    ;;; Grasps on the variable instance the
    ;;; Errorhandlers to - only in this call
    ;;; Environment! 
    (defun SAVE-UCS (/ UCSFLAG)
      (if (= INSTANCE 1)
        (progn
          (setq UCSFLAG (WORLD-UCS))
          (SAVE-VARS '(UCSFLAG) '*UCSDATA*)
        ) ;_ end of progn
      ) ;_ end of if
    ) ;_ end of defun


    ;;; Grasps on the variable instance the
    ;;; Errorhandlers to - only in this call
    ;;; Environment!
    (defun RESTORE-UCS (/ UCSFLAG)
      (if (= INSTANCE 1)
        (progn
          (RESTORE-VARS '*UCSDATA*)
          (PREVIOUS-UCS)
        ) ;_ end of progn
      ) ;_ end of if
    ) ;_ end of defun

    ;;; Puts an element on a pile off and gives it back
    ;;; necessarily for example for the restoring of user variable among others. 
    ;;;Arguments:
    ;;; ELM = name of the variables
    ;;; STACKSYM = name the stack
    (defun PUSH! (ELM STACKSYM /)
      (set STACKSYM (cons ELM (eval STACKSYM)))
      ELM
    ) ;_ end of defun


    ;;; Takes an element of a pile down and gives it back
    ;;; necessarily for example for the restoring of user variable among others. 
    ;;;Arguments:
    ;;; STACKSYM = name the stack
    (defun POP! (STACKSYM / ELM)
      (setq ELM (car (eval STACKSYM)))
      (set STACKSYM (cdr (eval STACKSYM)))
      ELM
    ) ;_ end of defun

    ;;; Sub-Function for the neutralizing of user variable on one stack
    ;;; arguments:
    ;;; VARS = list of variable name
    ;;; STACK = name the stack
    (defun SAVE-VARS (VARS STACK /)
      (foreach VAR VARS
        (PUSH! (cons VAR (eval VAR)) STACK)
      ) ;_ end of foreach
    ) ;_ end of defun

    ;;; Sub-Function for the restoring of user variable out of oneStack
    ;;; Argument:
    ;;; STACK = Name the Stacks
    (defun RESTORE-VARS (STACK / VAR)
      (repeat (length (eval STACK))
        (setq VAR (POP! STACK))
        (set (car VAR) (cdr VAR))
      ) ;_ end of repeat
    ) ;_ end of defun


.

------------------

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #14 on: February 07, 2006, 09:07:36 AM »
Thanks Mr t-bear
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #15 on: February 07, 2006, 10:35:22 AM »
Luis

I have tried that site in the past....broken links to the lessons.
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

LE

  • Guest
Re: Universal Error Function
« Reply #16 on: February 07, 2006, 10:44:45 AM »
Luis

I have tried that site in the past....broken links to the lessons.

I see, I saw them before.... though they were still in there.... my bad - [I will get rid of my previous post, is not valid then....]

JohnK

  • Administrator
  • Seagull
  • Posts: 10646
Re: Universal Error Function
« Reply #17 on: February 07, 2006, 10:45:13 AM »
There has been many of 'these' over the years. Although, I think my all time  favorite would be one by Vladimir Nesterovsky.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Universal Error Function
« Reply #18 on: February 07, 2006, 11:03:34 AM »
From the AU 2003 handouts listed on AUGI

There’s an Error in My Code! Now What?
Instructor:  R. Robert Bell

http://www.augi.com/education/auhandouts/2003/CP12-3.zip

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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Universal Error Function
« Reply #19 on: February 08, 2006, 04:27:56 AM »
Luis

I have tried that site in the past....broken links to the lessons.

I've sent a note to Bobby C Jones .. so keep the link handy .. perhaps ..

http://www.acadx.com/articles/008.htm
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.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: Universal Error Function
« Reply #20 on: February 08, 2006, 09:23:39 AM »
I sent an email to Frank O. about the broken links.....it was returned due to "Mailbox Full"

dan19936

  • Guest
Re: Universal Error Function
« Reply #21 on: February 09, 2006, 04:24:03 PM »
I scavanged those pdfs a while back, attached (I hope).

Dan

I sent an email to Frank O. about the broken links.....it was returned due to "Mailbox Full"

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Universal Error Function
« Reply #22 on: February 10, 2006, 02:20:01 PM »
I scavanged those pdfs a while back, attached (I hope).

I just got the files from Bob, but it looks like you beat me to it :-)  I hope this helps!
Bobby C. Jones

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Universal Error Function
« Reply #23 on: February 28, 2006, 05:17:09 PM »
I scavanged those pdfs a while back, attached (I hope).

Dan

I sent an email to Frank O. about the broken links.....it was returned due to "Mailbox Full"

Thanks Dan. Great !

and thanks Bobby for sanctioning the attachment .. not that there would be any doubt :)
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.

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Universal Error Function
« Reply #24 on: March 02, 2006, 01:53:35 PM »
and thanks Bobby for sanctioning the attachment .. not that there would be any doubt :)

Glad to help out.  And just to add to an already long list of posts, which I regretfully have not had a chance to read, here is something that I wrote many moons ago on this topic.  This covers the error function that I use in my lisp code.  Yes, I have lots of LISP code :-)

Quote
First we should have a short review of what an AutoLISP error handler is, what it does, and how it works.  An error handler is simply a function that is called when AutoCAD detects an error in a lisp routine.  When the error is detected, execution of the lisp routine halts and the error function is automatically called with an error message argument.  This message will vary depending on what caused the error.  For example; dividing a number by zero, (/ 2 0), will call the error handler with the message "divide by zero", (+ 1 "two") will return the message "bad argument type: numberp: "two"".  VisualLISP has a built-in error handler that will run in the event that we have not defined our own.  It does nothing more than exit cleanly from the running routine and report the error message to the command line.  It is also important to note that, starting with AutoCAD 2000 and beyond, all variables declared as local to a function will be cleared in the event of an error.  In the example below, the variables A, B, & C would all be set to nil without a custom error handler doing anything.

(defun myfunc (/ A B C)
  (setq A "A"
           B "B"
           C "C"
  )
  ;;Force an error
  (/ 2 0)
)

Note:  The most common error in a lisp routine is caused when the user hits the Escape key to exit the command.

Since variables are now automatically released, why do we need to bother with error handlers at all?   The program exits fairly cleanly to the command line, and cleans up the local variables.  That's a good start, but what about when a routine changes a system variable?  You do not want your program changing a users’ running object snaps just because it crashed.  Imagine how annoying and frustrating that is to the user.  Your routines should always reset the environment back to the way it was before it started, whether it exits normally or must handle an unusual event.  This is the main reason for implementing custom error handlers.  A custom error handler can also do things such as erase partially drawn objects that a lisp routine was drawing when a user hit the escape key.  It can be complex or simple.  Please note that custom error handlers are lisp routines themselves and should be kept as short and quick running as possible.  You don't want an error handler running long enough for a user to hit <escape> while it is running.  This will cause an error in the error handler and will keep the error handler from completing.  An error in a custom error handler will execute the default error handler, not recursively call itself.

Now that we know what an error handler is and what it's supposed to do, let's look at some code. This code is based upon functionality in AutoCAD 2000, or greater.

;;;example function #1
(defun myFunc (/ *error* blp osm)

  ;;Custom error handler
  (defun *error* (msg)
    (if (not (member
                 msg
                 '(nil "console break" "Function cancelled" "quit / exit abort")
                )
          )
      (princ (strcat "\nError: " msg))
    )

  (setvar "blipmode" blp)
  (setvar "osmode" omd)
  (princ)
  )
  (setq blp(getvar "blipmode")
          osm (getvar "osmode")
  )
  (setvar "blipmode" 0)
  (setvar "osmode" 0)
  ;;User interface functions
  (get some info from the user)
  ;;Core functions
  (draw some stuff with that info)
  (*error* nil)
)

  The first thing that some of you “old timers” may notice is that we no longer must go thru the gyrations of saving the old error handler to a variable and setting the error handler to our custom error handler.  That is accomplished by defining the *error* function in the scope of our routine by and declaring it as local to our routine.  Next you'll notice that, instead of resetting all of our system variables at the end of our routine, we are calling our error routine with a nil message argument to perform the reset for us.  This isn't really new, per say, but is most likely a new way of thinking for many.  This method keeps us from having to type in (setvar "cmdecho" cmd) etc. ad  nauseum, once at the end of a routine and again in the error handler.  If your routine changes several variables then that can be quite a bit of typing and prone to omissions.  This method works great and will make your routines have a professional look and feel to the end user.  Let’s step through the myFunc example function #1 above and determine what happens in the event of an error.

First, notice that we’ve defined the *error* function inside of the myFunc function and declared *error* as a local variable in our routine.  This way we will not interfere with any global custom *error* handler that may be running on the user’s system.  Next, we save the current value of some system variables and then change them to values that make sense in our routine.  At the end of the routine we manually call our *error* function with a nil argument.  The error function contains all the necessary code to reset our system variables back to their original settings and exit cleanly from the routine.  This is an outline for a simple error handler.  Nothing more elaborate is necessary; however I do suggest that you add a little cinnamon to that scoop of vanilla and spice up your error handler.

Listed below are several functions that make up my custom error handling routine.  These functions make the error handler “dynamic”.  This means that you can change what the error handler does in the middle of your routines. The original ideas that this code are based on come from an error handling system described in the book “Maximizing AutoLISP R12”, by Rusty Gesner & Joe Smith.

;;;Initialize custom *error* handler
(defun initerr ()
  ;;Function for adding application specific
  ;;actions to the *error* handler
  (defun-q reset () (setvar "menuecho" 1) (setvar "cmdecho" 1) (princ))
  ;;main error routine, redefines standard *error* function
  (defun *error* (msg)
    (setvar "cmdecho" 0)
    (if
      (not (member
             msg
             '("console break" "Function cancelled" "quit / exit abort")
           )
      )
       (progn
         (princ (strcat "\nError #" (itoa (getvar "errno")) ": " msg))
         (setvar "errno" 0)
       )
    )
    ;;cancel any active commands
    (while (< 0 (getvar "cmdactive"))
      (command)
    )
    (reset)
  )
)

;;;adds an item to the error list
;;;item must be a quoted expression
;;;example: (adderr '(command "erase" "last" ""))
;;;or in the form (adderr (list 'setvar "osmode" (getvar "osmode")))
(defun adderr (item)
  (if (not (member item reset))
    (setq reset (append '(nil) (list item) (cdr reset)))
  )
)

;;;deletes an item from the error list
;;;item is same format as adderr
;;;example (delerr '(command "erase" "last" ""))
(defun delerr (item)
  (setq reset (subst '() item reset))
)

;;;Adds a list of variables to be saved
;;;to the error list
;;;example (VarSave '(("highlight" . 0)
;;;                   "osmode")
;;;        )
;;;vars in the list with an included value
;;;will be changed to that value
(defun VarSave (varLst / varName)
  (foreach var varLst
    (setq varName (if (listp var) (car var) var))
    (adderr (list 'setvar varName (getvar varName)))
    (if (listp var)
      (setvar VarName (cdr var))
    )
  )
)

"How do you use these things?" you ask.  Let's look at the same example from above utilizing this code.

;;;example function #2
(defun myFunc (/ *error* A B C)
  ;;Initialize custom error handler
  (initerr)
  (varSave ‘((“blipmode . 1) (“osmode” . 0)))
  (get some info from the user)
  (draw some stuff with that info)
  (reset)
)

This function accomplishes the exact same thing as the first example in this article in a slightly different manner and with much less typing on your end.  Let's take a closer look at each individual function.

(initerr)
This function initializes the basic custom error handler by 1) defining (*error*) and 2) defining the (reset) function.  We know what the *error* function is, but what is this other (reset) function and why is it defined with that defun-q?

(reset)
This is the dynamic function that we can add to and delete from as our routines dictate, using either (varSave…), (adder…), (delerr…), or any other method available to us, to manipulate a list structure.  Before VisualLisp there was very little difference between our functions and our data.  A function defined with DEFUN was really just a glorified list.  We could add to and modify it with the same functions that we used to modify lists.  Now with the advent of VisualLisp, this is only possible if we define a function with (DEFUN-Q).  Therefore, in order for us to make our (reset) function dynamic, we must define it with (DEFUN-Q).  We'll demonstrate this technique in a minute.

(varSave)
This function helps to keep us from get carpel tunnel syndrome by reducing the amount of typing we have to do.  We simply provide a list of system variables, and the values that we want to temporarily switch them to, and the current values are saved and restored when the program completes or in the event of an error.  Look at these four lines from example #1 above:

  (setq blp(getvar "blipmode")
          osm (getvar "osmode")
  )
  (setvar "blipmode" 0)
  (setvar "osmode" 0)

All four of these lines have been replaced with this one simple call:
(varSave ‘((“blipmode . 1) (“osmode” . 0)))

(adderr)
This is the function that actually puts info into the (reset) function on the fly.

(delerr)
This is the antithesis of the (adderr) function.  It will remove items from the (reset) function.

So how does all this code work?   Look at the second example above.  We start by declaring *error* as local to each function that we are adding our error handler to.  Then, (initerr) is called to define the custom *error* handler.  When it is run, (initerr) defines the initial (reset) function which, when run, will execute this code:

  (setvar "menuecho" 1)
  (setvar "cmdecho" 1)
  (princ)

Next, we call (varSave) with our list of system variables and the values to change them to.  (varSave) is simply a front end to the (adderr) function.  It doesn’t really do anything more than call (adderr) with each provided system variable and then calls (setvar) with each corresponding value.  The first system variable in our list is “blipmode”.  (varSave) calls (adderr) which adds the code to (reset) to set the blipmode system variable to it's current setting and sets the current value to 0.  Running the (reset) function would now execute this code:

  (setvar "blipmode" 1)
  (setvar "menuecho 1)
  (setvar "cmdecho" 1)
  (princ)

and after (varSave) makes the second call to (adderr), if the original osmode system variable setting was 35:

  (setvar "osmode" 35)
  (setvar "blipmode" 1)
  (setvar "menuecho 1)
  (setvar "cmdecho" 1)
  (princ)

Now if an error occurs in our routine, the (*error*) function is called. It prints, or suppresses, the error message depending on what the error is, and then executes the (reset) function.  In fact, the (reset) function is called whether our code completes normally, or is terminated with an error.  This means that all of our system variables will be set back to their original settings in any event.  As far as the end user is concerned, the first code example runs exactly the same way as the second code example.  The difference to you, as the developer, is that you eliminated setting some variables, you are now able to dynamically add expressions to your error handler, and you did it all with much less typing.

Let’s look at another example of adding items dynamically to the error handler.  Let's say that we are collecting points from the user and interactively drawing a polyline between those points.  Now let us say that in the middle of this routine the user has selected several points and a pline was been drawn between those points, but he changes his mind and hits the escape key to terminate the custom command.  Normally this would leave the partial pline in the drawing and the user would have to go back and erase it.  But if just prior to collecting the points we add this to our routine:

  (adderr '(command "_.U"))

Now our (reset) function would execute this:
  (command "_.U")
  (setvar "osmode" 35)
  (setvar "blipmode" 1)
  (setvar "menuecho 1)
  (setvar "cmdecho" 1)
  (princ)

This would undo the partial pline, freeing the user from having to go back and erase it.  Very 'professional'.  I know you're thinking, "But what about when the routine ends? It will undo the pline then also!!".  To fix that we simply call the (delerr) function after we are sure that the user is finished selecting points.

  (delerr '(command "_.U"))

Now our (reset) function is set back to:

  (setvar "osmode" 35)
  (setvar "blipmode" 1)
  (setvar "menuecho 1)
  (setvar "cmdecho" 1)
  (princ)

Bobby C. Jones

GDF

  • Water Moccasin
  • Posts: 2081
Re: Universal Error Function
« Reply #25 on: March 02, 2006, 02:29:52 PM »
Thanks Bobby, I will read it.

Gary
Why is there never enough time to do it right, but always enough time to do it over?
BricsCAD 2020x64 Windows 10x64

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Universal Error Function
« Reply #26 on: March 02, 2006, 11:43:16 PM »
I just did, read it that is.
Well worth the time it took to read it.
Nice job.
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.

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: Universal Error Function
« Reply #27 on: March 03, 2006, 08:51:10 AM »
In the beginning of function I establish a list of the necessary environment variables,
list variable always miscellaneous:
Code: [Select]
(SETQ
  ERROR-LST-
             '("AUTOSNAP" "OSMODE" "APERTURE" "HPSPACE" "HPASSOC" "MIRRTEXT" "AUPREC" "LUPREC"
               "DIMZIN" "cecolor"
              )
  ERROR-LST- (mapcar (function (lambda (a) (list 'setvar a (getvar a)))) ERROR-LST-)
) ;_  SETQ
Function *error*
Code: [Select]
(defun *error* (msg) (MAPCAR 'eval ERROR-LST-))
It is a universal *error* function :-)

whdjr

  • Guest
Re: Universal Error Function
« Reply #28 on: March 03, 2006, 10:13:08 AM »
........, but what about when a routine changes a system variable?  You do not want your program changing a users’ running object snaps just because it crashed.  Imagine how annoying and frustrating that is to the user.  Your routines should always reset the environment back to the way it was before it started, whether it exits normally or must handle an unusual event.  This is the main reason for implementing custom error handlers.  A custom error handler can also do things such as erase partially drawn objects that a lisp routine was drawing when a user hit the escape key.  It can be complex or simple........

.........An error in a custom error handler will execute the default error handler........

..........First, notice that we’ve defined the *error* function inside of the myFunc function and declared *error* as a local variable in our routine.  This way we will not interfere with any global custom *error* handler that may be running on the user’s system......

..........At the end of the routine we manually call our *error* function with a nil argument.  The error function contains all the necessary code to reset our system variables back to their original settings and exit cleanly from the routine.  This is an outline for a simple error handler.  Nothing more elaborate is necessary; however I do suggest that you add a little cinnamon to that scoop of vanilla and spice up your error handler.

Bobby,
After we run our error handler would it be wise to force an error in the last line of our error handler so as to call the global error handler in case the user has modified the global error handler to his liking?

JohnK

  • Administrator
  • Seagull
  • Posts: 10646
Re: Universal Error Function
« Reply #29 on: March 03, 2006, 10:17:23 AM »
In the beginning of function I establish a list of the necessary environment variables,
list variable always miscellaneous:
<snip>
It is a universal *error* function :-)

Unbelievable!
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: Universal Error Function
« Reply #30 on: March 03, 2006, 10:26:41 AM »
Unbelievable!
Code: [Select]
(SETQ ERROR-LST- (cons '(alert " ERROR") ERROR-LST-))
(*error* "")

whdjr

  • Guest
Re: Universal Error Function
« Reply #31 on: March 03, 2006, 10:33:05 AM »
In the beginning of function I establish a list of the necessary environment variables,
list variable always miscellaneous:
<snip>
It is a universal *error* function :-)

Unbelievable!

WOW!  That is truely amazing.

Se7en,  there is you a great example of eval.

JohnK

  • Administrator
  • Seagull
  • Posts: 10646
Re: Universal Error Function
« Reply #32 on: March 03, 2006, 10:38:34 AM »
Will, I know how to USE eval, i want to know how it works. *smile* Did you every break apart a radio when you were a kid and try to see where the sound was comming from? ...Thats what im doing.

Elpanov, your code scares me. *lol* That little bit of code was so simple...Im speachless. wow.
TheSwamp.org (serving the CAD community since 2003)
Member location map - Add yourself

Donate to TheSwamp.org

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Universal Error Function
« Reply #33 on: March 03, 2006, 11:06:30 AM »
Bobby,
After we run our error handler would it be wise to force an error in the last line of our error handler so as to call the global error handler in case the user has modified the global error handler to his liking?

Nope.  If your routine successfully handles it then there is no more exceptional situation for a global error handler to handle.
Bobby C. Jones

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Universal Error Function
« Reply #34 on: March 03, 2006, 02:24:54 PM »
Elpanov
That's a cool routine! 8-)
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.

LE

  • Guest
Re: Universal Error Function
« Reply #35 on: March 03, 2006, 06:04:37 PM »
In the beginning of function I establish a list of the necessary environment variables,
list variable always miscellaneous:
It is a universal *error* function :-)

ElpanovEvgeniy;

Welcome to theSwamp... do not worried about your English...keep the good code coming.  :kewl:

Luis Esquivel

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: Universal Error Function
« Reply #36 on: March 05, 2006, 06:21:39 PM »
Code: [Select]
(SETQ ERROR-LST- (cons '(alert " ERROR") ERROR-LST-))
(*error* "")
I wish to add about (*ERROR* ""):
Code: [Select]
(SETQ ERROR-LST- (cons '(alert "ERROR ... 1") ERROR-LST-))
....
(SETQ ERROR-LST- (cons '(alert " ERROR ....2") (CDR ERROR-LST-)))

'(alert "ERROR") = Any function
Now you will understand, how I use *ERROR *! :-)

kpblc

  • Bull Frog
  • Posts: 396
Re: Universal Error Function
« Reply #37 on: March 06, 2006, 07:01:31 AM »
One more variant for error catcher:
Code: [Select]
;;; Error initializer
(defun kpblc-error (message)
  (if (member message
         '("console break"        "Function cancelled" "quit / exit abort")
         ) ;_member
    (princ "\nFunction cancelled by user")
    (princ
      (strcat "\ERRNO # "
         (itoa (getvar "ERRNO"))
         ": "
         message
         "\n"
         ) ;_strcat
      ) ;_princ
    ) ;_if
  (princ)
  ) ;_defun

;|=============================================================================
*    Saves system variables restore (sysvars saved at global list *kpblc-sysvar-list*)
*    Call params:
*    None
*    Call sample:
(kpblc-error-restore-sysvar)
=============================================================================|;
(defun kpblc-error-restore-sysvar   ()
  (if *kpblc-sysvar-list*
    (foreach item *kpblc-sysvar-list*
      (if (or (vl-catch-all-error-p
       (vl-catch-all-apply 'setvar (list (car item) (cadr item)))
       ) ;_ end of vl-catch-all-error-p
          (= (cadr item) "")
          (wcmatch (strcase (car item) r) "dim*")
          ) ;_ end of and
   (setvar (car item) ".")
   (setvar (car item) (cadr item))
   ) ;_ end of if
      ) ;_ end of foreach
    ) ;_ end of if
  (setq *kpblc-sysvar-list* nil)
  (gc)
  ) ;_ end of defun

;|=============================================================================
*    Saves current values of sysvars at global list *kpblc-sysvar-list* and definind new values for them.
*    Call params:
*   sysvar-list   - list of sysvars with their new values
*    Call samples:
(kpblc-error-sysvar-list (list '("cmdecho" 0) '("blipmode") '("osmode" 503)))
=======================================================================================|;
(defun kpblc-error-save-sysvar (sysvar-list)
  (foreach item   sysvar-list
    (setq *kpblc-sysvar-list*
      (cons
        (list (car item) (getvar (car item)))
        *kpblc-sysvar-list*
        ) ;_ end of cons
     ) ;_ end of setq   
    (if   (cadr item)
      (if (and (vl-catch-all-error-p
       (vl-catch-all-apply 'setvar (list (car item) (cadr item)))
       ) ;_ end of VL-CATCH-ALL-ERROR-P
          (= (cadr item) "")
          (wcmatch (strcase (car item) t) "dim*")
          ) ;_ end of and
   (setvar (car item) ".")
   (setvar (car item) (cadr item))
   ) ;_ end of if
      ) ;_ end of if
    ) ;_ end of foreach
  ) ;_ end of defun
and example for using:
Code: [Select]
(defun (some-function (param1 param2 / *error*)
(setq *error* kpblc-error)
(kpblc-error-save-sysvar '(("osmode" 0) ("cmdecho" 0)))
;;; Doing somethings
(kpblc-error-restore-sysvar)
)
Sorry for my English.