当你不想用 DCL 来交互程序的参数设置时,读取 ini 配置文件可以作为一个备用选择,也能方便用户修改。
AutoLISP 程序设计时常用的数据存储方式,各有优缺点:
1. 非图形对象数据字典
2. Windows 注册表
3. 磁盘文件
第一种方式,程序参数将随 DWG 图一起存储,当新开一个图形后,参数需要重新配置
第二种方式,不符合绿色软件的原则,不适合保存大量数据,如对象 DXF 码。有时候会被杀毒软件屏蔽。
第三种方式,LISP 找不到自己加载的路径,无法将参数文件和程序放在同一目录里
本程序为磁盘存储方式提供了统一接口,可以不设置路径,程序将在支持目录里搜索。
例如下面代码将保存一个对象的 dxf 码到ini文件,文件与当前 dwg 同路径。
(setq ss (strcat (getvar "DWGPREFIX") (getvar "DWGNAME") ".ini"))
(vl-ini-set (list ss "LIST表" "DXF" (entget(car(entsel)))))
如果需要读出刚刚保存的 dxf 数据
(vl-ini-get (list ss "LIST表" "DXF"))
程序源代码如下:
用 Lisp 对 INI 文件解析
版权所有 (c) by. yxp QQ:9034598 2015-08-16 明经通道
转载或引用,请注明作者和出处
功能:读取磁盘配置文件
语法: (vl-ini-get ini-list)
参数: ini-list 为表类型
ini-list = (inifile [section [key [default]]])
inifile 指定的INI文件
section INI文件中的段落
key INI文件中的关键字
default 若INI文件中没有关键字则默认返回值
返回值:
1、只含 INI文件 则返回所有段落名称
2、含 section 则返回指定段落下的所有关键字
3、含 key 则返回指定段落下的指定关键字的值,失败则返回 nil
4、含 default 则返回指定段落下的指定关键字的值,失败则返回 default
示例: (vl-ini-get "CAD.ini")
(vl-load-com)
;;配置文件类别,大写,程序运行过程中可修改, 如
;;(setq yxp_file_ext_key "*.TXT")
(setq yxp_file_ext_key "*.INI")
;;依赖顺序进行参数合法性判断 vl-ini-get
;;子函数3个: yxp_read_ini yxp_read_sec yxp_read_key
(defun vl-ini-get( ini-list / )
(cond
;;转到帮助
((or (= ini-list '?)(= ini-list "?"))(vl-ini-get-help)(princ))
;;判断参数是否表类型
((/= (type ini-list) 'List)(princ "\n; 错误: 要求表参数")(princ))
;;判断参数数量
((> (length ini-list) 4)(princ "\n; 错误: 表参数太多")(princ))
;;判断第一个表参数是否字符型
((/= (type (car ini-list)) 'Str)(princ "\n; 错误: 要求字符型参数")(princ))
;;判断文件名是否 yxp_file_ext_key 类型
((null (wcmatch (strcase (car ini-list)) yxp_file_ext_key))
(princ (strcat "\n; 错误: 不是有效的 " yxp_file_ext_key " 文件名"))(princ))
;;路径长度限制
((> (strlen (car ini-list)) 256)(princ "\n; 错误: 路径及文件名长度超限")(princ))
;;判断第一个参数是否路径
((null (findfile (car ini-list)))(princ "\n; 错误: 不能读取的路径或文件名称")(princ))
;;第二个参数不存在,则返回 ini 文件所有段落名
((null (cadr ini-list))(yxp_read_ini (car ini-list)))
;;判断第二个参数是否字符型
((/= (type (cadr ini-list)) 'Str)(princ "\n; 错误: 段落名称类型不正确")(princ))
;;判断段落名称是否合法,不能为空字符
((wcmatch (cadr ini-list) " ")(princ "\n; 错误: 段落名称不合法")(princ))
;;段落字符长度限制
((> (strlen (cadr ini-list)) 64)(princ "\n; 错误: 段落长度超限")(princ))
;;第三个参数不存在,则返回段落名下所有关键字
((null (caddr ini-list))(yxp_read_sec ini-list))
;;判断关键字是否字符型
((/= (type (caddr ini-list)) 'Str)(princ "\n; 错误: 关键字类型不正确")(princ))
;;关键字是否合法,不能包含 = ,不能是空格
((wcmatch (caddr ini-list) "*=*, ")(princ "\n; 错误: 关键字不合法")(princ))
;;关键字长度限制
((> (strlen (caddr ini-list)) 64)(princ "\n; 错误: 关键字长度超限")(princ))
;;返回关键字的值
(t (yxp_read_key ini-list))
)
)
;;返回所有段落名。 ss 文件名
(defun yxp_read_ini (ss / fn xx rowini)
(setq fn (open (findfile ss) "r"))
(while (setq xx (read-line fn))
(if (wcmatch xx "`[*`]")(setq rowini (cons (vl-string-trim "[ ]" xx) rowini)))
)
(close fn)
(reverse (vl-remove "" rowini)) ;;剔除空段落
)
;;返回指定段落的关键字列表。 ss 表: 文件名、段落
(defun yxp_read_sec(ss / fname sec fn xx FLAG secrow rows nn)
(setq fname (car ss) ;;文件名
sec (vl-string-trim " " (cadr ss)) ;;段落,删除前后空格
fn (open (findfile fname) "r"))
(while (setq xx (read-line fn))
(if (wcmatch xx "`[*`]") ;;匹配段落
(setq FLAG (= (vl-string-trim "[ ]" xx) sec))
) ;;搜到段落时 FLAG=T,开始记录关键字。
(if FLAG (setq rows (cons xx rows))) ;;读出指定段落的关键字
)(close fn)
(setq rows (cdr (reverse rows))) ;;删除第一行段落名,只留关键字
(while (setq xx (car rows))
(setq rows (cdr rows)
nn (vl-string-search "=" xx)) ;;关键字不合法时 nn=nil
(if nn (setq xx (vl-string-trim " " (substr xx 1 nn))
secrow (cons xx secrow)))
) (reverse secrow)
)
;;返回指定关键字的值。 ss 表: 文件名、段落名、关键字、值
(defun yxp_read_key (ss / fname sec fn xx secrow rows nn)
(setq fname (car ss)
sec (vl-string-trim " " (cadr ss))
key (vl-string-trim " " (caddr ss)) ;;关键字,删除前后空格
fn (open (findfile fname) "r"))
(while (setq xx (read-line fn))
(if (wcmatch xx "`[*`]")
(setq FLAG (= (vl-string-trim "[ ]" xx) sec))
)
(if FLAG (setq rows (cons xx rows)))
)(close fn)
(setq rows (cdr (reverse rows)))
(while (setq xx (car rows))
(setq rows (cdr rows)
nn (vl-string-search "=" xx)) ;;此前与 yxp_read_sec 函数相同
(if nn (setq secrow (cons (list (vl-string-trim " " (substr xx 1 nn)) (vl-string-trim " " (substr xx (+ 2 nn)))) secrow)))
)
(setq ff (cadr (assoc key (reverse secrow))))
(if ff ff (cadddr ss))
)
;;参数合法性判断 vl-ini-set
;;子函数 1 个: yxp_save_ini
(defun vl-ini-set( ini-list )
(cond
;;转到帮助
((or (= ini-list '?)(= ini-list "?"))(vl-ini-set-help)(princ))
;;判断参数是否表类型
((/= (type ini-list) 'List)(princ "\n; 错误: 要求表参数")(princ))
;;判断参数数量
((or (< (length ini-list) 2)(> (length ini-list) 4))
(princ "\n; 错误: 表参数不足或太多")(princ))
;;判断第一个表参数是否字符型
((/= (type (car ini-list)) 'Str)(princ "\n; 错误: 要求字符型参数")(princ))
;;判断文件名是否 yxp_file_ext_key 类型
((null (wcmatch (strcase (car ini-list)) yxp_file_ext_key))
(princ (strcat "\n; 错误: 不是有效的 " yxp_file_ext_key " 文件名"))(princ))
;;判断段落名是否字符型
((/= (type (cadr ini-list)) 'Str)(princ "\n; 错误: 段落名称类型不正确")(princ))
;;判断段落名称是否合法,不能为空字符
((wcmatch (cadr ini-list) " ")(princ "\n; 错误: 段落名称不合法")(princ))
;;判断第三个参数是否字符型
((and (caddr ini-list)(/= (type (caddr ini-list)) 'Str))
(princ "\n; 错误: 关键字类型不正确")(princ))
;;判断关键字是否合法,不能为空字符
((and (caddr ini-list)(wcmatch (caddr ini-list) " "))
(princ "\n; 错误: 关键字不合法")(princ))
;;前三个参数的字长限制
((or (> (strlen (car ini-list)) 256)(> (strlen (cadr ini-list)) 64)
(and (caddr ini-list) (> (strlen (caddr ini-list)) 64)))
(princ "\n; 错误: 参数字符长度超限")(princ))
;;如果第三个参数不存在,则保存段落名
(t (yxp_save_ini ini-list))
)
)
;; 读入 ini ,如果不存在,则创建, 如果存在,则修改
;; 算法:从后往前搜索段落名,找到后再从前往后搜索关键字
(defun yxp_save_ini (ss / C wc A B seq qq fa FLAG r1 r2 fb AA)
(setq fa (open (car ss) "r")
sec (vl-string-trim " " (cadr ss)))
(if (caddr ss)
(setq key (vl-string-trim " " (caddr ss))
qq (strcat key " = ")
wc (strcat key "=*," key " =*")))
(if (cadddr ss)(setq qq (strcat qq (vl-princ-to-string (cadddr ss)))))
(if fa (progn
(while (setq xx (read-line fa))(setq A (cons xx A)))
(close fa)
(setq AA A)
(if (caddr ss)(progn (while (setq r1 (car A)) (if (wcmatch (vl-string-trim " " r1) wc)(setq FLAG t)) (if (wcmatch r1 "`[*`]") (if (= (vl-string-trim "[ ]" r1) sec) (progn (if FLAG (progn (setq r2 (car B)) (while (null (wcmatch (vl-string-trim " " r2) wc)) (setq A (cons r2 A) B (cdr B) r2 (car B)) ) (setq C (append (reverse A) (cons qq (cdr B)))) ) (setq C (append (reverse A) (cons qq B))) ) (setq A nil)) (setq FLAG nil) ) ) (setq B (cons r1 B) A (cdr A)) ) ;; the end (if (null C)(setq C (cons (strcat "[" sec "]") (cons qq B)))) )(progn (while (setq r1 (car A)) (if (and (wcmatch r1 "`[*`]") (= (vl-string-trim "[ ]" r1) sec)) (setq A nil B nil) (setq B (cons r1 B) A (cdr A)) ) ) (setq C (if B (cons (strcat "[" sec "]") B))) )
)
(if (null AA)
(if (caddr ss) (setq C (list (strcat "[" sec "]") qq)) (setq C (list (strcat "[" sec "]"))))
))
(setq C (list (strcat "[" sec "]") (if qq qq "")))
)
(if C (progn
(setq fb (open (car ss) "w"))
(foreach x C (write-line x fb))
(close fb)
(if (= 3 (length ss)) "" (last ss))
))
)
(defun vl-ini-set-help()
(princ (strcat "\n"
"功能: 保存 ini 配置文件, 程序编写: yxp 2015-8-16" "\n"
"语法: (vl-ini-set ini-list)" "\n"
"参数: ini-list == (inifile section [key [value]])" "\n"
" inifile 必选, 字符型, 路径 + 文件名" "\n"
" section 必选, 字符型, 段落名, 长度不大于 64" "\n"
" key 可选, 字符型, 关键字, 长度不大于 64, 未设置时只保存段落" "\n"
" value 可选, 任意类型, 关键字的值, 长度不限, 未设置时关键字为空字符" "\n"
"返回值: 失败时返回 nil, 成功则返回保存的数据" "\n"
))
)
(defun vl-ini-get-help()
(princ (strcat "\n"
"功能: 读入 ini 配置文件, 程序编写: yxp 2015-8-16" "\n"
"语法: (vl-ini-get ini-list)" "\n"
"参数: ini-list == (inifile [section [key [default]]])" "\n"
" inifile 必选, 字符型, 路径 + 文件名" "\n"
" section 可选, 字符型, 段落名, 长度不大于 64" "\n"
" key 可选, 字符型, 关键字, 长度不大于 64" "\n"
" default 可选, 任意类型, 关键字的值, 长度不限" "\n"
"返回值:" "\n"
" 1、只含 inifile 返回所有段落名称" "\n"
" 2、仅含 section 返回指定段落下的所有关键字" "\n"
" 3、仅含 key 返回指定关键字的值,未找到关键字则返回 nil" "\n"
" 4、含 default 返回指定关键字的值,未找到则返回 default" "\n"
))
)
(princ)