Managing Configuration Files in AutoLISP

Monday, March 16, 2026

When developing an AutoLISP program, you often need to store configuration settings: an output directory, a unit of measurement, a naming prefix, etc.

The first instinct is to reach for a classic text format like .ini:

[general]
unit=cm
output-directory=C:\Output

But this requires writing a parser to read sections, keys, and values. It's doable, but tedious.

Leveraging AutoLISP Syntax

AutoLISP is a dialect of Lisp, and in Lisp, code and data share the same syntax: lists. So you can write a configuration file directly as an association list and load it with the built-in read function.

Here is an example configuration file Config.cfg:

(
  ("unit" . "cm")
  ("output-directory" . "C:\\Output")
)

This is a list of dotted pairs. Each pair associates a key (a string) with a value. It's the equivalent of a dictionary in Python or a Dictionary<string, string> in .NET.

Loading the Configuration

The load-configuration function opens the file, reads all lines, concatenates them, then uses read to convert the text into an AutoLISP list:

;;; Loads a configuration from a file (association list).
;;; path : path to the configuration file
;;; Returns the association list, or nil on error
(defun load-configuration (path / file content line configuration)
  (setq file (open path "r"))
  (if file
    (progn
      (setq content "")
      (while (setq line (read-line file))
        (setq content (strcat content line))
      )
      (close file)
      (setq configuration (read content))
      configuration
    )
    (progn
      (princ (strcat "\nError: unable to open file " path))
      nil
    )
  )
)

The magic happens at the (read content) line: AutoLISP's read function parses the text and rebuilds the data structure. No need to write a parser — the language handles it.

Reading and Modifying Values

Once the configuration is loaded into a global variable *CONFIG*, you can read a value with assoc and modify it with subst.

Naming convention: in AutoLISP, any variable not declared after the / in the argument list is global. To clearly distinguish global variables from local ones, a naming convention is used. Here, the asterisks around *CONFIG* immediately signal that it is a global variable. This notation is inspired by *error*, the well-known AutoLISP global function used to install a custom error handler. You can also use the $ prefix, for example $config. The important thing is to choose a convention and stick with it.

;;; Returns the value associated with a key in the configuration
(defun get-configuration-value (key)
  (cdr (assoc key *CONFIG*))
)

;;; Modifies or adds a value in the configuration
(defun set-configuration-value (key value / old)
  (setq old (assoc key *CONFIG*))
  (if old
    (setq *CONFIG* (subst (cons key value) old *CONFIG*))
    (setq *CONFIG* (cons (cons key value) *CONFIG*))
  )
)

The get-configuration-value function uses assoc to find the pair matching the key, then cdr to extract the value.

The set-configuration-value function handles two cases:

  • If the key already exists, subst replaces the old pair with the new one.
  • Otherwise, cons adds the new pair at the head of the list.

Usage Example

(defun C:TESTCONFIG ()
  (setq *CONFIG* (load-configuration "C:\\Temp\\Config.cfg"))
  (if *CONFIG*
    (progn
      (princ (strcat "\nUnit: " (get-configuration-value "unit")))
      (princ (strcat "\nOutput directory: " (get-configuration-value "output-directory")))
    )
    (princ "\nFailed to load configuration.")
  )
  (princ)
)

Result in the AutoCAD console:

Unit: cm
Output directory: C:\Output

Saving the Configuration

You can also write a function to save the modified configuration:

;;; Saves the configuration to a file
;;; path : path to the configuration file
;;; Returns T on success, nil otherwise
(defun save-configuration (path / file pair)
  (setq file (open path "w"))
  (if file
    (progn
      (write-line "(" file)
      (foreach pair *CONFIG*
        (write-line
          (strcat "  (\"" (car pair) "\" . \"" (cdr pair) "\")")
          file
        )
      )
      (write-line ")" file)
      (close file)
      T
    )
    (progn
      (princ (strcat "\nError: unable to write to file " path))
      nil
    )
  )
)

Each pair is written on a separate line to keep the file readable.

Conclusion

By using AutoLISP's native syntax as a data format, you get a simple and effective configuration system without having to write a parser. The read function does all the heavy lifting.


Helping hand Need an AutoCAD (AutoLISP, ObjectARX, .NET, VBA) development? Contact me for a free quote.