Merge lp:~anj/epics-base/compiled-dbd into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12271
Proposed branch: lp:~anj/epics-base/compiled-dbd
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 4157 lines (+3010/-686) (has conflicts)
43 files modified
configure/CONFIG_BASE (+4/-4)
configure/RULES.Db (+45/-5)
src/Makefile (+3/-0)
src/ioc/db/RULES (+8/-0)
src/ioc/db/dbCommon.dbd (+10/-10)
src/ioc/dbStatic/Makefile (+1/-17)
src/ioc/dbStatic/dbReadTest.c (+0/-90)
src/ioc/dbStatic/dbToMenuH.c (+0/-124)
src/ioc/dbStatic/dbToRecordtypeH.c (+0/-267)
src/ioc/registry/registerRecordDeviceDriver.pl (+167/-168)
src/tools/DBD.pm (+81/-0)
src/tools/DBD/Base.pm (+127/-0)
src/tools/DBD/Breaktable.pm (+32/-0)
src/tools/DBD/Device.pm (+45/-0)
src/tools/DBD/Driver.pm (+9/-0)
src/tools/DBD/Function.pm (+10/-0)
src/tools/DBD/Menu.pm (+66/-0)
src/tools/DBD/Output.pm (+98/-0)
src/tools/DBD/Parser.pm (+197/-0)
src/tools/DBD/Recfield.pm (+436/-0)
src/tools/DBD/Recordtype.pm (+100/-0)
src/tools/DBD/Registrar.pm (+11/-0)
src/tools/DBD/Variable.pm (+36/-0)
src/tools/EPICS/Readfile.pm (+101/-0)
src/tools/EPICS/macLib.pm (+251/-0)
src/tools/Makefile (+22/-1)
src/tools/dbdExpand.pl (+53/-0)
src/tools/dbdReport.pl (+64/-0)
src/tools/dbdToHtml.pl (+252/-0)
src/tools/dbdToMenuH.pl (+80/-0)
src/tools/dbdToRecordtypeH.pl (+231/-0)
src/tools/test/Breaktable.plt (+22/-0)
src/tools/test/DBD.plt (+60/-0)
src/tools/test/Device.plt (+33/-0)
src/tools/test/Driver.plt (+13/-0)
src/tools/test/Function.plt (+13/-0)
src/tools/test/Makefile (+26/-0)
src/tools/test/Menu.plt (+32/-0)
src/tools/test/Recfield.plt (+114/-0)
src/tools/test/Recordtype.plt (+57/-0)
src/tools/test/Registrar.plt (+13/-0)
src/tools/test/Variable.plt (+15/-0)
src/tools/test/macLib.plt (+72/-0)
Text conflict in configure/RULES.Db
Text conflict in src/ioc/db/RULES
Contents conflict in src/ioc/dbStatic/dbExpand.c
To merge this branch: bzr merge lp:~anj/epics-base/compiled-dbd
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Review via email: mp+97525@code.launchpad.net

Description of the change

This branch replaces the dbToMenuH, dbToRecordH and dbExpand programs with Perl versions that perform the same functionality but don't have to be compiled first. This fixes a dependency problem we're having at the moment with parallel builds on the 3.15 branch. The underlying Perl technology will also allow other improvements in DBD file handling, including eventually removing the need for the IOC load a DBD file, although that will need more work.

This also fixes the issue of someone using field names in a record type that happen to be C or C++ keywords.

I have not tested this code on Windows yet.

To post a comment you must log in.
lp:~anj/epics-base/compiled-dbd updated
12285. By Andrew Johnson

Convert registerRecordDeviceDriver.pl to use DBD module.

The output is now a bit more compact as it uses Text::Wrap on
the declarations and array data.

12286. By Andrew Johnson

Use the new DBD processing scripts to generate dependency files.

12287. By Andrew Johnson

configure: Clean up some other DBDEPENDS stuff

Revision history for this message
Andrew Johnson (anj) wrote :

I'm planning to merge this branch into the main trunk (3.15 series) very soon. It needs a little bit of work to merge cleanly, but I'll do that at the time.

- Andrew

Revision history for this message
Andrew Johnson (anj) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'configure/CONFIG_BASE'
--- configure/CONFIG_BASE 2011-02-27 00:24:51 +0000
+++ configure/CONFIG_BASE 2012-04-02 20:38:19 +0000
@@ -57,11 +57,11 @@
57# Epics base build tools and tool flags57# Epics base build tools and tool flags
5858
59MAKEBPT = $(call PATH_FILTER, $(TOOLS)/makeBpt$(HOSTEXE))59MAKEBPT = $(call PATH_FILTER, $(TOOLS)/makeBpt$(HOSTEXE))
60DBEXPAND = $(call PATH_FILTER, $(TOOLS)/dbExpand$(HOSTEXE))60DBEXPAND = $(PERL) $(TOOLS)/dbdExpand.pl
61DBTORECORDTYPEH = $(call PATH_FILTER, $(TOOLS)/dbToRecordtypeH$(HOSTEXE))61DBTORECORDTYPEH = $(PERL) $(TOOLS)/dbdToRecordtypeH.pl
62DBTOMENUH = $(call PATH_FILTER, $(TOOLS)/dbToMenuH$(HOSTEXE))62DBTOMENUH = $(PERL) $(TOOLS)/dbdToMenuH.pl
63REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl63REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
64CONVERTRELEASE=$(PERL) $(TOOLS)/convertRelease.pl64CONVERTRELEASE = $(PERL) $(TOOLS)/convertRelease.pl
6565
66#-------------------------------------------------------66#-------------------------------------------------------
67# tools for installing libraries and products67# tools for installing libraries and products
6868
=== modified file 'configure/RULES.Db'
--- configure/RULES.Db 2012-04-02 20:36:02 +0000
+++ configure/RULES.Db 2012-04-02 20:38:19 +0000
@@ -112,9 +112,6 @@
112 $(patsubst $(COMMON_DIR)/%,%,$(COMMON_DBS)) \112 $(patsubst $(COMMON_DIR)/%,%,$(COMMON_DBS)) \
113 $(patsubst $(COMMON_DIR)/%,%,$(COMMON_DBDS)))113 $(patsubst $(COMMON_DIR)/%,%,$(COMMON_DBDS)))
114114
115DBDDEPENDS_FLAGS = $(subst -I,,$(filter-out -S%,$(DBDFLAGS)))
116DBDDEPENDS_CMD = -$(MKMF) -m $(notdir $@)$(DEP) $(DBDDEPENDS_FLAGS) $@ $<
117
118MAKEDBDEPENDS = $(PERL) $(TOOLS)/makeDbDepends.pl115MAKEDBDEPENDS = $(PERL) $(TOOLS)/makeDbDepends.pl
119116
120##################################################### 117#####################################################
@@ -226,35 +223,63 @@
226223
227$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd224$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
228 @$(RM) $(notdir $@)$(DEP)225 @$(RM) $(notdir $@)$(DEP)
226<<<<<<< TREE
229 @$(DBDDEPENDS_CMD)227 @$(DBDDEPENDS_CMD)
230 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)228 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
231 @$(RM) $(notdir $@)229 @$(RM) $(notdir $@)
232 $(DBTORECORDTYPEH) $(DBDFLAGS) $< $(notdir $@)230 $(DBTORECORDTYPEH) $(DBDFLAGS) $< $(notdir $@)
233 @$(MV) $(notdir $@) $@231 @$(MV) $(notdir $@) $@
232=======
233 @$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
234 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
235 @$(RM) $@
236 $(DBTORECORDTYPEH) $(DBDFLAGS) -o $@ $<
237>>>>>>> MERGE-SOURCE
234238
235$(COMMON_DIR)/%Record.h: %Record.dbd239$(COMMON_DIR)/%Record.h: %Record.dbd
236 @$(RM) $(notdir $@)$(DEP)240 @$(RM) $(notdir $@)$(DEP)
241<<<<<<< TREE
237 @$(DBDDEPENDS_CMD)242 @$(DBDDEPENDS_CMD)
238 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)243 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
239 @$(RM) $(notdir $@)244 @$(RM) $(notdir $@)
240 $(DBTORECORDTYPEH) $(DBDFLAGS) $< $(notdir $@)245 $(DBTORECORDTYPEH) $(DBDFLAGS) $< $(notdir $@)
241 @$(MV) $(notdir $@) $@246 @$(MV) $(notdir $@) $@
247=======
248 @$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
249 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
250 @$(RM) $@
251 $(DBTORECORDTYPEH) $(DBDFLAGS) -o $@ $<
252>>>>>>> MERGE-SOURCE
242253
243$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd254$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd
244 @$(RM) $(notdir $@)$(DEP)255 @$(RM) $(notdir $@)$(DEP)
256<<<<<<< TREE
245 @$(DBDDEPENDS_CMD)257 @$(DBDDEPENDS_CMD)
246 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)258 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
247 @$(RM) $(notdir $@)259 @$(RM) $(notdir $@)
248 $(DBTOMENUH) $(DBDFLAGS) $< $(notdir $@)260 $(DBTOMENUH) $(DBDFLAGS) $< $(notdir $@)
249 @$(MV) $(notdir $@) $@261 @$(MV) $(notdir $@) $@
262=======
263 @$(DBTOMENUH) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
264 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
265 @$(RM) $@
266 $(DBTOMENUH) $(DBDFLAGS) -o $@ $<
267>>>>>>> MERGE-SOURCE
250268
251$(COMMON_DIR)/menu%.h: menu%.dbd269$(COMMON_DIR)/menu%.h: menu%.dbd
252 @$(RM) $(notdir $@)$(DEP)270 @$(RM) $(notdir $@)$(DEP)
271<<<<<<< TREE
253 @$(DBDDEPENDS_CMD)272 @$(DBDDEPENDS_CMD)
254 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)273 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
255 @$(RM) $(notdir $@)274 @$(RM) $(notdir $@)
256 $(DBTOMENUH) $(DBDFLAGS) $< $(notdir $@)275 $(DBTOMENUH) $(DBDFLAGS) $< $(notdir $@)
257 @$(MV) $(notdir $@) $@276 @$(MV) $(notdir $@) $@
277=======
278 @$(DBTOMENUH) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
279 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
280 @$(RM) $@
281 $(DBTOMENUH) $(DBDFLAGS) -o $@ $<
282>>>>>>> MERGE-SOURCE
258283
259.PRECIOUS: $(COMMON_DIR)/%.h284.PRECIOUS: $(COMMON_DIR)/%.h
260285
@@ -264,10 +289,15 @@
264 $(MAKEBPT) $< $(notdir $@)289 $(MAKEBPT) $< $(notdir $@)
265 @$(MV) $(notdir $@) $@290 @$(MV) $(notdir $@) $@
266291
267$(COMMON_DIR)/%.dbd: $(COMMON_DIR)/%Include.dbd 292$(COMMON_DIR)/%.dbd: $(COMMON_DIR)/%Include.dbd
268 @$(RM) $(notdir $@)$(DEP)293 @$(RM) $(notdir $@)$(DEP)
294<<<<<<< TREE
269 @$(DBDDEPENDS_CMD)295 @$(DBDDEPENDS_CMD)
270 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)296 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
297=======
298 @$(DBEXPAND) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
299 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
300>>>>>>> MERGE-SOURCE
271 $(ECHO) "Expanding dbd"301 $(ECHO) "Expanding dbd"
272 @$(RM) $(notdir $@)302 @$(RM) $(notdir $@)
273 @$(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $<303 @$(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $<
@@ -275,8 +305,13 @@
275305
276$(COMMON_DIR)/%.dbd: %Include.dbd 306$(COMMON_DIR)/%.dbd: %Include.dbd
277 @$(RM) $(notdir $@)$(DEP)307 @$(RM) $(notdir $@)$(DEP)
308<<<<<<< TREE
278 @$(DBDDEPENDS_CMD)309 @$(DBDDEPENDS_CMD)
279 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)310 echo "$< : ../Makefile" >> $(notdir $@)$(DEP)
311=======
312 @$(DBEXPAND) -D $(DBDFLAGS) -o $@ $< > $(notdir $@)$(DEP)
313 @echo "$@: ../Makefile" >> $(notdir $@)$(DEP)
314>>>>>>> MERGE-SOURCE
280 $(ECHO) "Expanding dbd"315 $(ECHO) "Expanding dbd"
281 @$(RM) $(notdir $@)316 @$(RM) $(notdir $@)
282 $(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $<317 $(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $<
@@ -313,8 +348,13 @@
313348
314$(COMMON_DIR)/%.db$(RAW): %.substitutions349$(COMMON_DIR)/%.db$(RAW): %.substitutions
315 @$(RM) $(notdir $@)$(DEP)350 @$(RM) $(notdir $@)$(DEP)
351<<<<<<< TREE
316 @$(MAKEDBDEPENDS) $@ $< $(TEMPLATE_FILENAME) >> $(notdir $@)$(DEP)352 @$(MAKEDBDEPENDS) $@ $< $(TEMPLATE_FILENAME) >> $(notdir $@)$(DEP)
317 echo "$@ : $(TEMPLATE_FILENAME)" >> $(notdir $@)$(DEP)353 echo "$@ : $(TEMPLATE_FILENAME)" >> $(notdir $@)$(DEP)
354=======
355 $(MAKEDBDEPENDS) $@ $< $(TEMPLATE_FILENAME) > $(notdir $@)$(DEP)
356 @echo "$@: $(TEMPLATE_FILENAME)" >> $(notdir $@)$(DEP)
357>>>>>>> MERGE-SOURCE
318 $(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"358 $(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
319 @$(RM) $@ $*.tmp359 @$(RM) $@ $*.tmp
320 $(MSI) $(DBFLAGS) -S$< $(TEMPLATE_FILENAME) > $*.tmp360 $(MSI) $(DBFLAGS) -S$< $(TEMPLATE_FILENAME) > $*.tmp
@@ -322,7 +362,7 @@
322362
323$(COMMON_DIR)/%.db$(RAW): %.template363$(COMMON_DIR)/%.db$(RAW): %.template
324 @$(RM) $(notdir $@)$(DEP)364 @$(RM) $(notdir $@)$(DEP)
325 @$(MAKEDBDEPENDS) $@ $^ >> $(notdir $@)$(DEP)365 @$(MAKEDBDEPENDS) $@ $< > $(notdir $@)$(DEP)
326 $(ECHO) "Inflating database from $<"366 $(ECHO) "Inflating database from $<"
327 @$(RM) $@ $*.tmp367 @$(RM) $@ $*.tmp
328 $(MSI) $(DBFLAGS) $< > $*.tmp368 $(MSI) $(DBFLAGS) $< > $*.tmp
329369
=== modified file 'src/Makefile'
--- src/Makefile 2011-02-27 00:24:51 +0000
+++ src/Makefile 2012-04-02 20:38:19 +0000
@@ -15,6 +15,9 @@
1515
16DIRS += tools16DIRS += tools
1717
18DIRS += tools/test
19tools/test_DEPEND_DIRS = tools
20
18DIRS += template/base21DIRS += template/base
19template/base_DEPEND_DIRS = tools22template/base_DEPEND_DIRS = tools
2023
2124
=== modified file 'src/ioc/db/RULES'
--- src/ioc/db/RULES 2011-11-15 00:25:13 +0000
+++ src/ioc/db/RULES 2012-04-02 20:38:19 +0000
@@ -15,6 +15,7 @@
1515
16# $(filter-out $(STATIC_SRCS),$(dbCore_SRCS)) : $(COMMON_DIR)/dbCommon.h16# $(filter-out $(STATIC_SRCS),$(dbCore_SRCS)) : $(COMMON_DIR)/dbCommon.h
1717
18<<<<<<< TREE
18dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/dbCommon.dbd19dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/dbCommon.dbd
19 @$(RM) $@20 @$(RM) $@
20 @$(MKMF) -m $@ ../db $(COMMON_DIR)/dbCommon.h $<21 @$(MKMF) -m $@ ../db $(COMMON_DIR)/dbCommon.h $<
@@ -29,3 +30,10 @@
29$(patsubst %,$(COMMON_DIR)/%.h,$(DBDINC) menuConvert menuGlobal) : \30$(patsubst %,$(COMMON_DIR)/%.h,$(DBDINC) menuConvert menuGlobal) : \
30$(COMMON_DIR)/%.h : $(DBTOMENUH)31$(COMMON_DIR)/%.h : $(DBTOMENUH)
3132
33=======
34$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd
35 @$(RM) $(notdir $@)$(DEP)
36 @$(DBTORECORDTYPEH) -D -I ../db -o $@ $< > $(notdir $@)$(DEP)
37 $(RM) $@
38 $(DBTORECORDTYPEH) -I ../db -o $@ $<
39>>>>>>> MERGE-SOURCE
3240
=== modified file 'src/ioc/db/dbCommon.dbd'
--- src/ioc/db/dbCommon.dbd 2009-04-23 20:35:02 +0000
+++ src/ioc/db/dbCommon.dbd 2012-04-02 20:38:19 +0000
@@ -82,14 +82,14 @@
82 prompt("Monitor lock")82 prompt("Monitor lock")
83 special(SPC_NOMOD)83 special(SPC_NOMOD)
84 interest(4)84 interest(4)
85 extra("epicsMutexId mlok")85 extra("epicsMutexId mlok")
86 }86 }
87 %#include "ellLib.h"87 %#include "ellLib.h"
88 field(MLIS,DBF_NOACCESS) {88 field(MLIS,DBF_NOACCESS) {
89 prompt("Monitor List")89 prompt("Monitor List")
90 special(SPC_NOMOD)90 special(SPC_NOMOD)
91 interest(4)91 interest(4)
92 extra("ELLLIST mlis")92 extra("ELLLIST mlis")
93 }93 }
94 field(DISP,DBF_UCHAR) {94 field(DISP,DBF_UCHAR) {
95 prompt("Disable putField")95 prompt("Disable putField")
@@ -167,13 +167,13 @@
167 prompt("Access Security Pvt")167 prompt("Access Security Pvt")
168 special(SPC_NOMOD)168 special(SPC_NOMOD)
169 interest(4)169 interest(4)
170 extra("struct asgMember *asp")170 extra("struct asgMember *asp")
171 }171 }
172 field(PPN,DBF_NOACCESS) {172 field(PPN,DBF_NOACCESS) {
173 prompt("addr of PUTNOTIFY")173 prompt("addr of PUTNOTIFY")
174 special(SPC_NOMOD)174 special(SPC_NOMOD)
175 interest(4)175 interest(4)
176 extra("struct putNotify *ppn")176 extra("struct putNotify *ppn")
177 }177 }
178 field(PPNR,DBF_NOACCESS) {178 field(PPNR,DBF_NOACCESS) {
179 prompt("pputNotifyRecord")179 prompt("pputNotifyRecord")
@@ -191,19 +191,19 @@
191 prompt("Address of RSET")191 prompt("Address of RSET")
192 special(SPC_NOMOD)192 special(SPC_NOMOD)
193 interest(4)193 interest(4)
194 extra("struct rset *rset")194 extra("struct rset *rset")
195 }195 }
196 field(DSET,DBF_NOACCESS) {196 field(DSET,DBF_NOACCESS) {
197 prompt("DSET address")197 prompt("DSET address")
198 special(SPC_NOMOD)198 special(SPC_NOMOD)
199 interest(4)199 interest(4)
200 extra("struct dset *dset")200 extra("struct dset *dset")
201 }201 }
202 field(DPVT,DBF_NOACCESS) {202 field(DPVT,DBF_NOACCESS) {
203 prompt("Device Private")203 prompt("Device Private")
204 special(SPC_NOMOD)204 special(SPC_NOMOD)
205 interest(4)205 interest(4)
206 extra("void *dpvt")206 extra("void *dpvt")
207 }207 }
208 field(RDES,DBF_NOACCESS) {208 field(RDES,DBF_NOACCESS) {
209 prompt("Address of dbRecordType")209 prompt("Address of dbRecordType")
@@ -215,7 +215,7 @@
215 prompt("Lock Set")215 prompt("Lock Set")
216 special(SPC_NOMOD)216 special(SPC_NOMOD)
217 interest(4)217 interest(4)
218 extra("struct lockRecord *lset")218 extra("struct lockRecord *lset")
219 }219 }
220 field(PRIO,DBF_MENU) {220 field(PRIO,DBF_MENU) {
221 prompt("Scheduling Priority")221 prompt("Scheduling Priority")
@@ -231,7 +231,7 @@
231 prompt("Break Point")231 prompt("Break Point")
232 special(SPC_NOMOD)232 special(SPC_NOMOD)
233 interest(1)233 interest(1)
234 extra("char bkpt")234 extra("char bkpt")
235 }235 }
236 field(UDF,DBF_UCHAR) {236 field(UDF,DBF_UCHAR) {
237 prompt("Undefined")237 prompt("Undefined")
@@ -245,7 +245,7 @@
245 prompt("Time")245 prompt("Time")
246 special(SPC_NOMOD)246 special(SPC_NOMOD)
247 interest(2)247 interest(2)
248 extra("epicsTimeStamp time")248 extra("epicsTimeStamp time")
249 }249 }
250 field(FLNK,DBF_FWDLINK) {250 field(FLNK,DBF_FWDLINK) {
251 prompt("Forward Process Link")251 prompt("Forward Process Link")
252252
=== modified file 'src/ioc/dbStatic/Makefile'
--- src/ioc/dbStatic/Makefile 2011-09-15 19:05:05 +0000
+++ src/ioc/dbStatic/Makefile 2012-04-02 20:38:19 +0000
@@ -32,26 +32,10 @@
32dbCore_SRCS += dbStaticIocRegister.c32dbCore_SRCS += dbStaticIocRegister.c
3333
34dbStaticHost_SRCS += $(STATIC_SRCS)34dbStaticHost_SRCS += $(STATIC_SRCS)
35dbStaticHost_SRCS += dbStaticNoRun.c 35dbStaticHost_SRCS += dbStaticNoRun.c
3636
37LIBRARY_HOST += dbStaticHost37LIBRARY_HOST += dbStaticHost
3838
39dbStaticHost_LIBS = Com39dbStaticHost_LIBS = Com
4040
41PROD_HOST += dbReadTest dbExpand dbToMenuH dbToRecordtypeH
42
43dbReadTest_SRCS = dbReadTest.c
44dbExpand_SRCS = dbExpand.c
45dbToMenuH_SRCS = dbToMenuH.c
46dbToRecordtypeH_SRCS = dbToRecordtypeH.c
47
48# Include dbStaticHost objects directly in executables
49# because of a Circular dependency induced by a rule
50# $(INSTALL_LIBS): $(INSTALL_SHRLIBS)
51# in RULES_BUILD
52dbReadTest_SRCS += $(dbStaticHost_SRCS)
53dbExpand_SRCS += $(dbStaticHost_SRCS)
54dbToMenuH_SRCS += $(dbStaticHost_SRCS)
55dbToRecordtypeH_SRCS += $(dbStaticHost_SRCS)
56
57CLEANS += dbLex.c dbYacc.c41CLEANS += dbLex.c dbYacc.c
5842
=== renamed file 'src/ioc/dbStatic/dbExpand.c' => 'src/ioc/dbStatic/dbExpand.c.THIS'
=== removed file 'src/ioc/dbStatic/dbReadTest.c'
--- src/ioc/dbStatic/dbReadTest.c 2004-07-08 14:43:45 +0000
+++ src/ioc/dbStatic/dbReadTest.c 1970-01-01 00:00:00 +0000
@@ -1,90 +0,0 @@
1/*************************************************************************\
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.7
7* and higher are distributed subject to a Software License Agreement found
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/
10/* dbReadTest.c */
11/* Author: Marty Kraimer Date: 13JUL95 */
12
13#include <stdlib.h>
14#include <stddef.h>
15#include <stdio.h>
16#include <string.h>
17
18#include "dbDefs.h"
19#include "epicsPrint.h"
20#include "errMdef.h"
21#include "dbStaticLib.h"
22#include "dbStaticPvt.h"
23#include "dbBase.h"
24#include "gpHash.h"
25#include "osiFileName.h"
26
27DBBASE *pdbbase = NULL;
28
290
30int main(int argc,char **argv)
31{
32 int i;
33 int strip;
34 char *path = NULL;
35 char *sub = NULL;
36 int pathLength = 0;
37 int subLength = 0;
38 char **pstr;
39 char *psep;
40 int *len;
41 long status;
42 static char *pathSep = OSI_PATH_LIST_SEPARATOR;
43 static char *subSep = ",";
44
45 /*Look for options*/
46 if(argc<2) {
47 printf("usage: dbReadTest -Idir -Smacsub file.dbd file.db \n");
48 exit(0);
49 }
50 while((strncmp(argv[1],"-I",2)==0)||(strncmp(argv[1],"-S",2)==0)) {
51 if(strncmp(argv[1],"-I",2)==0) {
52 pstr = &path;
53 psep = pathSep;
54 len = &pathLength;
55 } else {
56 pstr = &sub;
57 psep = subSep;
58 len = &subLength;
59 }
60 if(strlen(argv[1])==2) {
61 dbCatString(pstr,len,argv[2],psep);
62 strip = 2;
63 } else {
64 dbCatString(pstr,len,argv[1]+2,psep);
65 strip = 1;
66 }
67 argc -= strip;
68 for(i=1; i<argc; i++) argv[i] = argv[i + strip];
69 }
70 if(argc<2 || (strncmp(argv[1],"-",1)==0)) {
71 printf("usage: dbReadTest -Idir -Idir file.dbd file.dbd \n");
72 exit(0);
73 }
74 for(i=1; i<argc; i++) {
75 status = dbReadDatabase(&pdbbase,argv[i],path,sub);
76 if(!status) continue;
77 fprintf(stderr,"For input file %s",argv[i]);
78 errMessage(status,"from dbReadDatabase");
79 }
80/*
81 dbDumpRecordType(pdbbase,"ai");
82 dbDumpRecordType(pdbbase,NULL);
83 dbPvdDump(pdbbase,1);
84 gphDump(pdbbase->pgpHash);
85 dbDumpMenu(pdbbase,NULL);
86 dbDumpRecord(pdbbase,NULL,0);
87 dbReportDeviceConfig(pdbbase,stdout);
88*/
89 dbFreeBase(pdbbase);
90 return(0);
91}
921
=== removed file 'src/ioc/dbStatic/dbToMenuH.c'
--- src/ioc/dbStatic/dbToMenuH.c 2008-08-05 22:48:45 +0000
+++ src/ioc/dbStatic/dbToMenuH.c 1970-01-01 00:00:00 +0000
@@ -1,124 +0,0 @@
1/*************************************************************************\
2* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* EPICS BASE Versions 3.13.7
7* and higher are distributed subject to a Software License Agreement found
8* in file LICENSE that is included with this distribution.
9\*************************************************************************/
10/* dbToMenu.c */
11/* Author: Marty Kraimer Date: 11Sep95 */
12#include <stdlib.h>
13#include <stddef.h>
14#include <stdio.h>
15#include <string.h>
16
17#include "dbDefs.h"
18#include "epicsPrint.h"
19#include "errMdef.h"
20#include "dbStaticLib.h"
21#include "dbStaticPvt.h"
22#include "dbBase.h"
23#include "gpHash.h"
24#include "osiFileName.h"
25
26DBBASE *pdbbase = NULL;
27
280
29int main(int argc,char **argv)
30{
31 dbMenu *pdbMenu;
32 char *outFilename;
33 char *pext;
34 FILE *outFile;
35 char *plastSlash;
36 int i;
37 int strip;
38 char *path = NULL;
39 char *sub = NULL;
40 int pathLength = 0;
41 int subLength = 0;
42 char **pstr;
43 char *psep;
44 int *len;
45 long status;
46 static char *pathSep = OSI_PATH_LIST_SEPARATOR;
47 static char *subSep = ",";
48
49 /*Look for options*/
50 if(argc<2) {
51 fprintf(stderr,"usage: dbToMenu -Idir -Idir file.dbd [outfile]\n");
52 exit(0);
53 }
54 while((strncmp(argv[1],"-I",2)==0)||(strncmp(argv[1],"-S",2)==0)) {
55 if(strncmp(argv[1],"-I",2)==0) {
56 pstr = &path;
57 psep = pathSep;
58 len = &pathLength;
59 } else {
60 pstr = &sub;
61 psep = subSep;
62 len = &subLength;
63 }
64 if(strlen(argv[1])==2) {
65 dbCatString(pstr,len,argv[2],psep);
66 strip = 2;
67 } else {
68 dbCatString(pstr,len,argv[1]+2,psep);
69 strip = 1;
70 }
71 argc -= strip;
72 for(i=1; i<argc; i++) argv[i] = argv[i + strip];
73 }
74 if(argc<2 || (strncmp(argv[1],"-",1)==0)) {
75 fprintf(stderr,"usage: dbToMenu -Idir -Idir file.dbd [outfile]\n");
76 exit(0);
77 }
78 if (argc==2) {
79 /*remove path so that outFile is created where program is executed*/
80 plastSlash = strrchr(argv[1],'/');
81 if(!plastSlash) plastSlash = strrchr(argv[1],'\\');
82 plastSlash = (plastSlash ? plastSlash+1 : argv[1]);
83 outFilename = dbCalloc(1,strlen(plastSlash)+1);
84 strcpy(outFilename,plastSlash);
85 pext = strstr(outFilename,".dbd");
86 if (!pext) {
87 fprintf(stderr,"Input file MUST have .dbd extension\n");
88 exit(-1);
89 }
90 strcpy(pext,".h");
91 } else {
92 outFilename = dbCalloc(1,strlen(argv[2])+1);
93 strcpy(outFilename,argv[2]);
94 }
95 pdbbase = dbAllocBase();
96 pdbbase->ignoreMissingMenus = TRUE;
97 status = dbReadDatabase(&pdbbase,argv[1],path,sub);
98 if (status) {
99 errlogFlush();
100 fprintf(stderr, "dbToMenuH: Input errors, no output generated\n");
101 exit(1);
102 }
103 outFile = fopen(outFilename, "w");
104 if (!outFile) {
105 epicsPrintf("Error creating output file \"%s\"\n", outFilename);
106 exit(1);
107 }
108 pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
109 while(pdbMenu) {
110 fprintf(outFile,"#ifndef INC%sH\n",pdbMenu->name);
111 fprintf(outFile,"#define INC%sH\n",pdbMenu->name);
112 fprintf(outFile,"typedef enum {\n");
113 for(i=0; i<pdbMenu->nChoice; i++) {
114 fprintf(outFile,"\t%s",pdbMenu->papChoiceName[i]);
115 if(i < (pdbMenu->nChoice - 1)) fprintf(outFile,",");
116 fprintf(outFile,"\n");
117 }
118 fprintf(outFile,"}%s;\n",pdbMenu->name);
119 fprintf(outFile,"#endif /*INC%sH*/\n",pdbMenu->name);
120 pdbMenu = (dbMenu *)ellNext(&pdbMenu->node);
121 }
122 fclose(outFile);
123 free((void *)outFilename);
124 return(0);
125}
1261
=== removed file 'src/ioc/dbStatic/dbToRecordtypeH.c'
--- src/ioc/dbStatic/dbToRecordtypeH.c 2008-08-05 22:48:45 +0000
+++ src/ioc/dbStatic/dbToRecordtypeH.c 1970-01-01 00:00:00 +0000
@@ -1,267 +0,0 @@
1/*************************************************************************\
2* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
3* National Laboratory.
4* Copyright (c) 2002 The Regents of the University of California, as
5* Operator of Los Alamos National Laboratory.
6* EPICS BASE is distributed subject to a Software License Agreement found
7* in file LICENSE that is included with this distribution.
8\*************************************************************************/
9/* dbToRecordtypeH.c */
10/* Author: Marty Kraimer Date: 11Sep95 */
11
12#include <stdlib.h>
13#include <stddef.h>
14#include <stdio.h>
15#include <string.h>
16#include <ctype.h>
17
18#include "dbDefs.h"
19#include "epicsPrint.h"
20#include "errMdef.h"
21#include "dbStaticLib.h"
22#include "dbStaticPvt.h"
23#include "dbBase.h"
24#include "gpHash.h"
25#include "osiFileName.h"
26
27DBBASE *pdbbase = NULL;
28
290
30int main(int argc,char **argv)
31{
32 int i;
33 char *outFilename;
34 char *pext;
35 FILE *outFile;
36 dbMenu *pdbMenu;
37 dbRecordType *pdbRecordType;
38 dbFldDes *pdbFldDes;
39 dbText *pdbCdef;
40 int isdbCommonRecord = FALSE;
41 char *plastSlash;
42 int strip;
43 char *path = NULL;
44 char *sub = NULL;
45 int pathLength = 0;
46 int subLength = 0;
47 char **pstr;
48 char *psep;
49 int *len;
50 long status;
51 static char *pathSep = OSI_PATH_LIST_SEPARATOR;
52 static char *subSep = ",";
53
54 /*Look for options*/
55 if(argc<2) {
56 fprintf(stderr,"usage: dbToRecordtypeH -Idir -Idir file.dbd [outfile]\n");
57 exit(0);
58 }
59 while((strncmp(argv[1],"-I",2)==0)||(strncmp(argv[1],"-S",2)==0)) {
60 if(strncmp(argv[1],"-I",2)==0) {
61 pstr = &path;
62 psep = pathSep;
63 len = &pathLength;
64 } else {
65 pstr = &sub;
66 psep = subSep;
67 len = &subLength;
68 }
69 if(strlen(argv[1])==2) {
70 dbCatString(pstr,len,argv[2],psep);
71 strip = 2;
72 } else {
73 dbCatString(pstr,len,argv[1]+2,psep);
74 strip = 1;
75 }
76 argc -= strip;
77 for(i=1; i<argc; i++) argv[i] = argv[i + strip];
78 }
79 if(argc<2 || (strncmp(argv[1],"-",1)==0)) {
80 fprintf(stderr,"usage: dbToRecordtypeH -Idir -Idir file.dbd [outfile]\n");
81 exit(0);
82 }
83 if(argc==2){
84 /*remove path so that outFile is created where program is executed*/
85 plastSlash = strrchr(argv[1],'/');
86 if(!plastSlash) plastSlash = strrchr(argv[1],'\\');
87 plastSlash = (plastSlash ? plastSlash+1 : argv[1]);
88 outFilename = dbCalloc(1,strlen(plastSlash)+1);
89 strcpy(outFilename,plastSlash);
90 pext = strstr(outFilename,".dbd");
91 if(!pext) {
92 fprintf(stderr,"Input file MUST have .dbd extension\n");
93 exit(-1);
94 }
95 strcpy(pext,".h");
96 if(strcmp(outFilename,"dbCommonRecord.h")==0) {
97 strcpy(outFilename,"dbCommon.h");
98 isdbCommonRecord = TRUE;
99 }
100 }else {
101 outFilename = dbCalloc(1,strlen(argv[2])+1);
102 strcpy(outFilename,argv[2]);
103 if(strstr(outFilename,"dbCommon.h")!=0) {
104 isdbCommonRecord = TRUE;
105 }
106 }
107 pdbbase = dbAllocBase();
108 pdbbase->ignoreMissingMenus = TRUE;
109 pdbbase->loadCdefs = TRUE;
110 status = dbReadDatabase(&pdbbase,argv[1],path,sub);
111 if(status) {
112 errlogFlush();
113 fprintf(stderr, "dbToMenuH: Input errors, no output generated\n");
114 exit(1);
115 }
116 outFile = fopen(outFilename,"w");
117 if(!outFile) {
118 epicsPrintf("Error creating output file \"%s\"\n", outFilename);
119 exit(1);
120 }
121
122 pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
123 while(pdbMenu) {
124 fprintf(outFile,"\n#ifndef INC%sH\n",pdbMenu->name);
125 fprintf(outFile,"#define INC%sH\n",pdbMenu->name);
126 fprintf(outFile,"typedef enum {\n");
127 for(i=0; i<pdbMenu->nChoice; i++) {
128 fprintf(outFile,"\t%s",pdbMenu->papChoiceName[i]);
129 if(i < (pdbMenu->nChoice - 1)) fprintf(outFile,",");
130 fprintf(outFile,"\n");
131 }
132 fprintf(outFile,"}%s;\n",pdbMenu->name);
133 fprintf(outFile,"#endif /*INC%sH*/\n",pdbMenu->name);
134 pdbMenu = (dbMenu *)ellNext(&pdbMenu->node);
135 }
136 pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
137 while(pdbRecordType) {
138 fprintf(outFile,"#ifndef INC%sH\n",pdbRecordType->name);
139 fprintf(outFile,"#define INC%sH\n",pdbRecordType->name);
140 pdbCdef = (dbText *)ellFirst(&pdbRecordType->cdefList);
141 while (pdbCdef) {
142 fprintf(outFile,"%s\n",pdbCdef->text);
143 pdbCdef = (dbText *)ellNext(&pdbCdef->node);
144 }
145 fprintf(outFile,"typedef struct %s",pdbRecordType->name);
146 if(!isdbCommonRecord) fprintf(outFile,"Record");
147 fprintf(outFile," {\n");
148 for(i=0; i<pdbRecordType->no_fields; i++) {
149 char name[256];
150 int j;
151
152 pdbFldDes = pdbRecordType->papFldDes[i];
153 for(j=0; j< (int)strlen(pdbFldDes->name); j++)
154 name[j] = tolower(pdbFldDes->name[j]);
155 name[strlen(pdbFldDes->name)] = 0;
156 switch(pdbFldDes->field_type) {
157 case DBF_STRING :
158 fprintf(outFile, "\tchar\t\t%s[%d];\t/* %s */\n",
159 name, pdbFldDes->size, pdbFldDes->prompt);
160 break;
161 case DBF_CHAR :
162 fprintf(outFile, "\tepicsInt8\t%s;\t/* %s */\n",
163 name, pdbFldDes->prompt);
164 break;
165 case DBF_UCHAR :
166 fprintf(outFile, "\tepicsUInt8\t%s;\t/* %s */\n",
167 name, pdbFldDes->prompt);
168 break;
169 case DBF_SHORT :
170 fprintf(outFile, "\tepicsInt16\t%s;\t/* %s */\n",
171 name, pdbFldDes->prompt);
172 break;
173 case DBF_USHORT :
174 fprintf(outFile, "\tepicsUInt16\t%s;\t/* %s */\n",
175 name, pdbFldDes->prompt);
176 break;
177 case DBF_LONG :
178 fprintf(outFile, "\tepicsInt32\t%s;\t/* %s */\n",
179 name, pdbFldDes->prompt);
180 break;
181 case DBF_ULONG :
182 fprintf(outFile, "\tepicsUInt32\t%s;\t/* %s */\n",
183 name, pdbFldDes->prompt);
184 break;
185 case DBF_FLOAT :
186 fprintf(outFile, "\tepicsFloat32\t%s;\t/* %s */\n",
187 name, pdbFldDes->prompt);
188 break;
189 case DBF_DOUBLE :
190 fprintf(outFile, "\tepicsFloat64\t%s;\t/* %s */\n",
191 name, pdbFldDes->prompt);
192 break;
193 case DBF_ENUM :
194 case DBF_MENU :
195 case DBF_DEVICE :
196 fprintf(outFile, "\tepicsEnum16\t%s;\t/* %s */\n",
197 name, pdbFldDes->prompt);
198 break;
199 case DBF_INLINK :
200 case DBF_OUTLINK :
201 case DBF_FWDLINK :
202 fprintf(outFile, "\tDBLINK\t\t%s;\t/* %s */\n",
203 name, pdbFldDes->prompt);
204 break;
205 case DBF_NOACCESS:
206 fprintf(outFile, "\t%s;\t/* %s */\n",
207 pdbFldDes->extra, pdbFldDes->prompt);
208 break;
209 default:
210 fprintf(outFile,"ILLEGAL FIELD TYPE\n");
211 }
212 }
213 fprintf(outFile,"} %s",pdbRecordType->name);
214 if(!isdbCommonRecord) fprintf(outFile,"Record");
215 fprintf(outFile,";\n");
216 if(!isdbCommonRecord) {
217 for(i=0; i<pdbRecordType->no_fields; i++) {
218 pdbFldDes = pdbRecordType->papFldDes[i];
219 fprintf(outFile,"#define %sRecord%s\t%d\n",
220 pdbRecordType->name,pdbFldDes->name,pdbFldDes->indRecordType);
221 }
222 }
223 fprintf(outFile,"#endif /*INC%sH*/\n",pdbRecordType->name);
224 pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node);
225 if(pdbRecordType) fprintf(outFile,"\n");
226 }
227 if(!isdbCommonRecord) {
228 fprintf(outFile,"#ifdef GEN_SIZE_OFFSET\n");
229 fprintf(outFile,"#ifdef __cplusplus\n");
230 fprintf(outFile,"extern \"C\" {\n");
231 fprintf(outFile,"#endif\n");
232 fprintf(outFile,"#include <epicsExport.h>\n");
233 pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
234 while(pdbRecordType) {
235 fprintf(outFile,"static int %sRecordSizeOffset(dbRecordType *pdbRecordType)\n{\n",
236 pdbRecordType->name);
237 fprintf(outFile," %sRecord *prec = 0;\n",pdbRecordType->name);
238 for(i=0; i<pdbRecordType->no_fields; i++) {
239 char name[256];
240 int j;
241
242 pdbFldDes = pdbRecordType->papFldDes[i];
243 for(j=0; j< (int)strlen(pdbFldDes->name); j++)
244 name[j] = tolower(pdbFldDes->name[j]);
245 name[strlen(pdbFldDes->name)] = 0;
246 fprintf(outFile,
247 " pdbRecordType->papFldDes[%d]->size=sizeof(prec->%s);\n",
248 i,name);
249 fprintf(outFile," pdbRecordType->papFldDes[%d]->offset=",i);
250 fprintf(outFile,
251 "(short)((char *)&prec->%s - (char *)prec);\n",name);
252 }
253 fprintf(outFile," pdbRecordType->rec_size = sizeof(*prec);\n");
254 fprintf(outFile," return(0);\n");
255 fprintf(outFile,"}\n");
256 fprintf(outFile,"epicsExportRegistrar(%sRecordSizeOffset);\n",
257 pdbRecordType->name);
258 pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node);
259 }
260 fprintf(outFile,"#ifdef __cplusplus\n");
261 fprintf(outFile,"}\n");
262 fprintf(outFile,"#endif\n");
263 fprintf(outFile,"#endif /*GEN_SIZE_OFFSET*/\n");
264 }
265 fclose(outFile);
266 free((void *)outFilename);
267 return(0);
268}
2691
=== modified file 'src/ioc/registry/registerRecordDeviceDriver.pl'
--- src/ioc/registry/registerRecordDeviceDriver.pl 2010-12-16 23:02:15 +0000
+++ src/ioc/registry/registerRecordDeviceDriver.pl 2012-04-02 20:38:19 +0000
@@ -1,7 +1,7 @@
1eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-1eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
2 if $running_under_some_shell; # registerRecordDeviceDriver 2 if $running_under_some_shell; # registerRecordDeviceDriver
3#*************************************************************************3#*************************************************************************
4# Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne4# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.5# National Laboratory.
6# Copyright (c) 2002 The Regents of the University of California, as6# Copyright (c) 2002 The Regents of the University of California, as
7# Operator of Los Alamos National Laboratory.7# Operator of Los Alamos National Laboratory.
@@ -9,52 +9,35 @@
9# in file LICENSE that is included with this distribution. 9# in file LICENSE that is included with this distribution.
10#*************************************************************************10#*************************************************************************
1111
12use strict;
13
12use FindBin qw($Bin);14use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";15use lib "$Bin/../../lib/perl";
16
17use DBD;
18use DBD::Parser;
19use EPICS::Readfile;
14use EPICS::Path;20use EPICS::Path;
1521use Text::Wrap;
16($file, $subname, $bldTop) = @ARGV;22
17$numberRecordType = 0;23my ($file, $subname, $bldTop) = @ARGV;
18$numberDeviceSupport = 0;24
19$numberDriverSupport = 0;25my $dbd = DBD->new();
26&ParseDBD($dbd, &Readfile($file));
27
28$Text::Wrap::columns = 75;
2029
21# Eliminate chars not allowed in C symbol names30# Eliminate chars not allowed in C symbol names
22$c_bad_ident_chars = '[^0-9A-Za-z_]';31my $c_bad_ident_chars = '[^0-9A-Za-z_]';
23$subname =~ s/$c_bad_ident_chars/_/g;32$subname =~ s/$c_bad_ident_chars/_/g;
2433
25# Process bldTop like convertRelease.pl does34# Process bldTop like convertRelease.pl does
26$bldTop = LocalPath(UnixPath($bldTop));35$bldTop = LocalPath(UnixPath($bldTop));
27$bldTop =~ s/([\\"])/\\\1/g; # escape back-slashes and double-quotes36$bldTop =~ s/([\\"])/\\\1/g; # escape back-slashes and double-quotes
2837
29open(INP,"$file") or die "$! opening file";38
30while(<INP>) {39# Start of generated file
31 next if m/ ^ \s* \# /x;40
32 if (m/ \b recordtype \s* \( \s* (\w+) \s* \) /x) {
33 $recordType[$numberRecordType++] = $1;
34 }
35 elsif (m/ \b device \s* \( \s* (\w+) \W+ \w+ \W+ (\w+) /x) {
36 $deviceRecordType[$numberDeviceSupport] = $1;
37 $deviceSupport[$numberDeviceSupport] = $2;
38 $numberDeviceSupport++;
39 }
40 elsif (m/ \b driver \s* \( \s* (\w+) \s* \) /x) {
41 $driverSupport[$numberDriverSupport++] = $1;
42 }
43 elsif (m/ \b registrar \s* \( \s* (\w+) \s* \) /x) {
44 push @registrars, $1;
45 }
46 elsif (m/ \b function \s* \( \s* (\w+) \s* \) /x) {
47 push @registrars, "register_func_$1";
48 }
49 elsif (m/ \b variable \s* \( \s* (\w+) \s* , \s* (\w+) \s* \) /x) {
50 $varType{$1} = $2;
51 push @variables, $1;
52 }
53}
54close(INP) or die "$! closing file";
55
56
57# beginning of generated routine
58print << "END" ;41print << "END" ;
59/* THIS IS A GENERATED FILE. DO NOT EDIT! */42/* THIS IS A GENERATED FILE. DO NOT EDIT! */
60/* Generated from $file */43/* Generated from $file */
@@ -70,104 +53,115 @@
7053
71END54END
7255
73#definitions for recordtype56my %rectypes = %{$dbd->recordtypes};
74if($numberRecordType>0) {57my @dsets;
75 for ($i=0; $i<$numberRecordType; $i++) {58if (%rectypes) {
76 print "epicsShareExtern rset *pvar_rset_$recordType[$i]RSET;\n";59 my @rtypnames = sort keys %rectypes;
77 print "epicsShareExtern int (*pvar_func_$recordType[$i]RecordSizeOffset)(dbRecordType *pdbRecordType);\n"60
78 }61 # Declare the record support entry tables
79 print "\nstatic const char * const recordTypeNames[$numberRecordType] = {\n";62 print wrap('epicsShareExtern rset ', ' ',
80 for ($i=0; $i<$numberRecordType; $i++) {63 join(', ', map {"*pvar_rset_${_}RSET"} @rtypnames)), ";\n\n";
81 print " \"$recordType[$i]\"";64
82 if($i < $numberRecordType-1) { print ",";}65 # Declare the RecordSizeOffset functions
83 print "\n";66 print "typedef int (*rso_func)(dbRecordType *pdbRecordType);\n";
84 }67 print wrap('epicsShareExtern rso_func ', ' ',
85 print "};\n\n";68 join(', ', map {"pvar_func_${_}RecordSizeOffset"} @rtypnames)), ";\n\n";
8669
87 print "static const recordTypeLocation rtl[$i] = {\n";70 # List of record type names
88 for ($i=0; $i<$numberRecordType; $i++) {71 print "static const char * const recordTypeNames[] = {\n";
89 print " {pvar_rset_$recordType[$i]RSET, pvar_func_$recordType[$i]RecordSizeOffset}";72 print wrap(' ', ' ', join(', ', map {"\"$_\""} @rtypnames));
90 if($i < $numberRecordType-1) { print ",";}73 print "\n};\n\n";
91 print "\n";74
92 }75 # List of pointers to each RSET and RecordSizeOffset function
93 print "};\n\n";76 print "static const recordTypeLocation rtl[] = {\n";
94}77 print join(",\n", map {
9578 " {pvar_rset_${_}RSET, pvar_func_${_}RecordSizeOffset}"
96#definitions for device79 } @rtypnames);
97if($numberDeviceSupport>0) {80 print "\n};\n\n";
98 for ($i=0; $i<$numberDeviceSupport; $i++) {81
99 print "epicsShareExtern dset *pvar_dset_$deviceSupport[$i];\n";82 for my $rtype (@rtypnames) {
100 }83 my @devices = $rectypes{$rtype}->devices;
101 print "\nstatic const char * const deviceSupportNames[$numberDeviceSupport] = {\n";84 for my $dtype (@devices) {
102 for ($i=0; $i<$numberDeviceSupport; $i++) {85 my $dset = $dtype->name;
103 print " \"$deviceSupport[$i]\"";86 push @dsets, $dset;
104 if($i < $numberDeviceSupport-1) { print ",";}87 }
105 print "\n";88 }
106 }89
107 print "};\n\n";90 if (@dsets) {
10891 # Declare the device support entry tables
109 print "static const dset * const devsl[$i] = {\n";92 print wrap('epicsShareExtern dset ', ' ',
110 for ($i=0; $i<$numberDeviceSupport; $i++) {93 join(', ', map {"*pvar_dset_$_"} @dsets)), ";\n\n";
111 print " pvar_dset_$deviceSupport[$i]";94
112 if($i < $numberDeviceSupport-1) { print ",";}95 # List of dset names
113 print "\n";96 print "static const char * const deviceSupportNames[] = {\n";
114 }97 print wrap(' ', ' ', join(', ', map {"\"$_\""} @dsets));
115 print "};\n\n";98 print "\n};\n\n";
116}99
117100 # List of pointers to each dset
118#definitions for driver101 print "static const dset * const devsl[] = {\n";
119if($numberDriverSupport>0) {102 print wrap(' ', ' ', join(", ", map {"pvar_dset_$_"} @dsets));
120 for ($i=0; $i<$numberDriverSupport; $i++) {103 print "\n};\n\n";
121 print "epicsShareExtern drvet *pvar_drvet_$driverSupport[$i];\n";104 }
122 }105}
123 print "\nstatic const char *driverSupportNames[$numberDriverSupport] = {\n";106
124 for ($i=0; $i<$numberDriverSupport; $i++) {107my %drivers = %{$dbd->drivers};
125 print " \"$driverSupport[$i]\"";108if (%drivers) {
126 if($i < $numberDriverSupport-1) { print ",";}109 my @drivers = sort keys %drivers;
127 print "\n";110
128 }111 # Declare the driver entry tables
129 print "};\n\n";112 print wrap('epicsShareExtern drvet ', ' ',
130 113 join(', ', map {"*pvar_drvet_$_"} @drivers)), ";\n\n";
131 print "static struct drvet *drvsl[$i] = {\n";114
132 for ($i=0; $i<$numberDriverSupport; $i++) {115 # List of drvet names
133 print " pvar_drvet_$driverSupport[$i]";116 print "static const char *driverSupportNames[] = {\n";
134 if($i < $numberDriverSupport-1) { print ",";}117 print wrap(' ', ' ', join(', ', map {"\"$_\""} @drivers));
135 print "\n";118 print "};\n\n";
136 }119
137 print "};\n\n";120 # List of pointers to each drvet
138}121 print "static struct drvet *drvsl[] = {\n";
139122 print join(",\n", map {" pvar_drvet_$_"} @drivers);
140#definitions registrar123 print "};\n\n";
141if(@registrars) {124}
142 foreach $reg (@registrars) {125
143 print "epicsShareExtern void (*pvar_func_$reg)(void);\n";126my @registrars = sort keys %{$dbd->registrars};
144 }127my @functions = sort keys %{$dbd->functions};
145 print "\n";128push @registrars, map {"register_func_$_"} @functions;
146}129if (@registrars) {
147130 # Declare the registrar functions
148if (@variables) {131 print "typedef void (*reg_func)(void);\n";
149 foreach $var (@variables) {132 print wrap('epicsShareExtern reg_func ', ' ',
150 print "epicsShareExtern $varType{$var} *pvar_$varType{$var}_$var;\n";133 join(', ', map {"pvar_func_$_"} @registrars)), ";\n\n";
151 }134}
152 %iocshTypes = (135
153 'int' => 'iocshArgInt',136my %variables = %{$dbd->variables};
154 'double' => 'iocshArgDouble'137if (%variables) {
155 );138 my @varnames = sort keys %variables;
156 print "static struct iocshVarDef vardefs[] = {\n";139
157 foreach $var (@variables) {140 # Declare the variables
158 $argType = $iocshTypes{$varType{$var}};141 for my $var (@varnames) {
159 die "Unknown variable type $varType{$var} for variable $var"142 my $vtype = $variables{$var}->var_type;
160 unless $argType;143 print "epicsShareExtern $vtype * const pvar_${vtype}_$var;\n";
161 print "\t{\"$var\", $argType, (void * const)pvar_$varType{$var}_$var},\n";144 }
162 }145
163 print "\t{NULL, iocshArgInt, NULL}\n};\n\n";146 # Generate the structure for registering variables with iocsh
164}147 print "\nstatic struct iocshVarDef vardefs[] = {\n";
165148 for my $var (@varnames) {
166#Now actual registration code.149 my $vtype = $variables{$var}->var_type;
167150 my $itype = $variables{$var}->iocshArg_type;
168print "int $subname(DBBASE *pbase)\n{\n";151 print " {\"$var\", $itype, pvar_${vtype}_$var},\n";
169152 }
170print << "END" if ($bldTop ne '') ;153 print " {NULL, iocshArgInt, NULL}\n};\n\n";
154}
155
156# Now for actual registration routine
157
158print << "END";
159int $subname(DBBASE *pbase)
160{
161 static int executed = 0;
162END
163
164print << "END" if $bldTop ne '';
171 const char *bldTop = "$bldTop";165 const char *bldTop = "$bldTop";
172 const char *envTop = getenv("TOP");166 const char *envTop = getenv("TOP");
173167
@@ -179,57 +173,62 @@
179173
180END174END
181175
182print << "END" ;176print << 'END';
183 if (!pbase) {177 if (!pbase) {
184 printf("pdbbase is NULL; you must load a DBD file first.\\n");178 printf("pdbbase is NULL; you must load a DBD file first.\n");
185 return -1;179 return -1;
186 }180 }
187181
188END182 if (executed) {
189183 printf("Registration already done.\n");
190if($numberRecordType>0) {184 return 0;
191 print " registerRecordTypes(pbase, $numberRecordType, ",185 }
192 "recordTypeNames, rtl);\n";186 executed = 1;
193}187
194if($numberDeviceSupport>0) {188END
195 print " registerDevices(pbase, $numberDeviceSupport, ",189
196 "deviceSupportNames, devsl);\n";190print << 'END' if %rectypes;
197}191 registerRecordTypes(pbase, NELEMENTS(rtl), recordTypeNames, rtl);
198if($numberDriverSupport>0) {192END
199 print " registerDrivers(pbase, $numberDriverSupport, ",193
200 "driverSupportNames, drvsl);\n";194print << 'END' if @dsets;
201}195 registerDevices(pbase, NELEMENTS(devsl), deviceSupportNames, devsl);
202foreach $reg (@registrars) {196END
203 print " (*pvar_func_$reg)();\n";197
204}198print << 'END' if %drivers;
205199 registerDrivers(pbase, NELEMENTS(drvsl), driverSupportNames, drvsl);
206if (@variables) {200END
207 print " iocshRegisterVariable(vardefs);\n";201
208}202print << "END" for @registrars;
209print << "END" ;203 pvar_func_$_();
204END
205
206print << 'END' if %variables;
207 iocshRegisterVariable(vardefs);
208END
209
210print << "END";
210 return 0;211 return 0;
211}212}
212213
213/* registerRecordDeviceDriver */214/* $subname */
214static const iocshArg registerRecordDeviceDriverArg0 =215static const iocshArg rrddArg0 = {"pdbbase", iocshArgPdbbase};
215 {"pdbbase",iocshArgPdbbase};216static const iocshArg *rrddArgs[] = {&rrddArg0};
216static const iocshArg *registerRecordDeviceDriverArgs[1] =217static const iocshFuncDef rrddFuncDef =
217 {&registerRecordDeviceDriverArg0};218 {"$subname", 1, rrddArgs};
218static const iocshFuncDef registerRecordDeviceDriverFuncDef =219static void rrddCallFunc(const iocshArgBuf *)
219 {"$subname",1,registerRecordDeviceDriverArgs};
220static void registerRecordDeviceDriverCallFunc(const iocshArgBuf *)
221{220{
222 $subname(*iocshPpdbbase);221 $subname(*iocshPpdbbase);
223}222}
224223
225} // extern "C"224} // extern "C"
225
226/*226/*
227 * Register commands on application startup227 * Register commands on application startup
228 */228 */
229static int Registration() {229static int Registration() {
230 iocshRegisterCommon();230 iocshRegisterCommon();
231 iocshRegister(&registerRecordDeviceDriverFuncDef,231 iocshRegister(&rrddFuncDef, rrddCallFunc);
232 registerRecordDeviceDriverCallFunc);
233 return 0;232 return 0;
234}233}
235234
236235
=== added directory 'src/tools/DBD'
=== added file 'src/tools/DBD.pm'
--- src/tools/DBD.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,81 @@
1package DBD;
2
3use DBD::Base;
4use DBD::Breaktable;
5use DBD::Driver;
6use DBD::Menu;
7use DBD::Recordtype;
8use DBD::Recfield;
9use DBD::Registrar;
10use DBD::Function;
11use DBD::Variable;
12
13use Carp;
14
15sub new {
16 my ($class) = @_;
17 my $this = {
18 'DBD::Breaktable' => {},
19 'DBD::Driver' => {},
20 'DBD::Function' => {},
21 'DBD::Menu' => {},
22 'DBD::Recordtype' => {},
23 'DBD::Registrar' => {},
24 'DBD::Variable' => {}
25 };
26 bless $this, $class;
27 return $this;
28}
29
30sub add {
31 my ($this, $obj) = @_;
32 my $obj_class;
33 foreach (keys %{$this}) {
34 next unless m/^DBD::/;
35 $obj_class = $_ and last if $obj->isa($_);
36 }
37 confess "Unknown object type"
38 unless defined $obj_class;
39 my $obj_name = $obj->name;
40 dieContext("Duplicate name '$obj_name'")
41 if exists $this->{$obj_class}->{$obj_name};
42 $this->{$obj_class}->{$obj_name} = $obj;
43}
44
45sub breaktables {
46 return shift->{'DBD::Breaktable'};
47}
48
49sub drivers {
50 return shift->{'DBD::Driver'};
51}
52
53sub functions {
54 return shift->{'DBD::Function'};
55}
56
57sub menus {
58 return shift->{'DBD::Menu'};
59}
60sub menu {
61 my ($this, $menu_name) = @_;
62 return $this->{'DBD::Menu'}->{$menu_name};
63}
64
65sub recordtypes {
66 return shift->{'DBD::Recordtype'};
67}
68sub recordtype {
69 my ($this, $rtyp_name) = @_;
70 return $this->{'DBD::Recordtype'}->{$rtyp_name};
71}
72
73sub registrars {
74 return shift->{'DBD::Registrar'};
75}
76
77sub variables {
78 return shift->{'DBD::Variable'};
79}
80
811;
082
=== added file 'src/tools/DBD/Base.pm'
--- src/tools/DBD/Base.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Base.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,127 @@
1# Common utility functions used by the DBD components
2
3package DBD::Base;
4
5use Carp;
6require Exporter;
7
8@ISA = qw(Exporter);
9@EXPORT = qw(&pushContext &popContext &dieContext &warnContext &is_reserved
10 &identifier &unquote &escapeCcomment &escapeCstring $RXident $RXname
11 $RXuint $RXint $RXhex $RXoct $RXuintx $RXintx $RXnum $RXdqs $RXsqs $RXstr);
12
13
14our $RXident = qr/ [a-zA-Z] [a-zA-Z0-9_]* /x;
15our $RXname = qr/ [a-zA-Z0-9_\-:.<>;]+ /x;
16our $RXhex = qr/ (?: 0 [xX] [0-9A-Fa-f]+ ) /x;
17our $RXoct = qr/ 0 [0-7]* /x;
18our $RXuint = qr/ \d+ /x;
19our $RXint = qr/ -? $RXuint /ox;
20our $RXuintx = qr/ ( $RXhex | $RXoct | $RXuint ) /ox;
21our $RXintx = qr/ ( $RXhex | $RXoct | $RXint ) /ox;
22our $RXnum = qr/ -? (?: \d+ | \d* \. \d+ ) (?: [eE] [-+]? \d+ )? /x;
23our $RXdqs = qr/" (?: [^"] | \\" )* " /x;
24our $RXsqs = qr/' (?: [^'] | \\' )* ' /x;
25our $RXstr = qr/ ( $RXname | $RXnum | $RXdqs | $RXsqs ) /ox;
26
27our @context;
28
29
30sub pushContext {
31 my ($ctxt) = @_;
32 unshift @context, $ctxt;
33}
34
35sub popContext {
36 my ($ctxt) = @_;
37 my ($pop) = shift @context;
38 ($ctxt ne $pop) and
39 dieContext("Exiting context \"$ctxt\", found \"$pop\" instead.",
40 "\tBraces must close in the same file they were opened.");
41}
42
43sub dieContext {
44 my ($msg) = join "\n\t", @_;
45 print "$msg\n" if $msg;
46 die "Context: ", join(' in ', @context), "\n";
47}
48
49sub warnContext {
50 my ($msg) = join "\n\t", @_;
51 print "$msg\n" if $msg;
52 print "Context: ", join(' in ', @context), "\n";
53}
54
55
56# Input checking
57
58sub unquote (\$) {
59 my ($s) = @_;
60 $$s =~ s/^"(.*)"$/$1/o;
61 return $$s;
62}
63
64# Reserved words from C++ and the DB/DBD file parser
65my %reserved = map { $_ => undef } qw(and and_eq asm auto bitand bitor bool
66 break case catch char class compl const const_cast continue default delete
67 do double dynamic_cast else enum explicit export extern false float for
68 friend goto if inline int long mutable namespace new not not_eq operator or
69 or_eq private protected public register reinterpret_cast return short signed
70 sizeof static static_cast struct switch template this throw true try typedef
71 typeid typename union unsigned using virtual void volatile wchar_t while xor
72 xor_eq addpath alias breaktable choice device driver field function grecord
73 include info menu path record recordtype registrar variable);
74sub is_reserved {
75 my $id = shift;
76 return exists $reserved{$id};
77}
78
79sub identifier {
80 my ($id, $what) = @_;
81 unquote $id;
82 confess "$what undefined!" unless defined $id;
83 $id =~ m/^$RXident$/o or dieContext("Illegal $what '$id'",
84 "Identifiers are used in C code so must start with a letter, followed",
85 "by letters, digits and/or underscore characters only.");
86 dieContext("Illegal $what '$id'",
87 "Identifier is a C++ reserved word.")
88 if is_reserved($id);
89 return $id;
90}
91
92
93# Output filtering
94
95sub escapeCcomment {
96 ($_) = @_;
97 s/\*\//**/g;
98 return $_;
99}
100
101sub escapeCstring {
102 ($_) = @_;
103 # How to do this?
104 return $_;
105}
106
107
108# Base class routines for the DBD component objects
109
110sub new {
111 my $class = shift;
112 my $this = {};
113 bless $this, $class;
114 return $this->init(@_);
115}
116
117sub init {
118 my ($this, $name, $what) = @_;
119 $this->{NAME} = identifier($name, $what);
120 return $this;
121}
122
123sub name {
124 return shift->{NAME};
125}
126
1271;
0128
=== added file 'src/tools/DBD/Breaktable.pm'
--- src/tools/DBD/Breaktable.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Breaktable.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,32 @@
1package DBD::Breaktable;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5use Carp;
6
7sub init {
8 my ($this, $name) = @_;
9 $this->SUPER::init($name, "breakpoint table name");
10 $this->{POINT_LIST} = [];
11 return $this;
12}
13
14sub add_point {
15 my ($this, $raw, $eng) = @_;
16 confess "Raw value undefined!" unless defined $raw;
17 confess "Engineering value undefined!" unless defined $eng;
18 unquote $raw;
19 unquote $eng;
20 push @{$this->{POINT_LIST}}, [$raw, $eng];
21}
22
23sub points {
24 return @{shift->{POINT_LIST}};
25}
26
27sub point {
28 my ($this, $idx) = @_;
29 return $this->{POINT_LIST}[$idx];
30}
31
321;
033
=== added file 'src/tools/DBD/Device.pm'
--- src/tools/DBD/Device.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Device.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,45 @@
1package DBD::Device;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5my %link_types = (
6 CONSTANT => qr/$RXnum/o,
7 PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox,
8 VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox,
9 CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox,
10 RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,
11 AB_IO => qr/\# (?: \s* [LACS] \s* $RXintx)* \s* (?: @ .*)?/ox,
12 GPIB_IO => qr/\# (?: \s* [LA] \s* $RXintx)* \s* (?: @ .*)?/ox,
13 BITBUS_IO => qr/\# (?: \s* [LNPS] \s* $RXuintx)* \s* (?: @ .*)?/ox,
14 BBGPIB_IO => qr/\# (?: \s* [LBG] \s* $RXuintx)* \s* (?: @ .*)?/ox,
15 VXI_IO => qr/\# (?: \s* [VCS] \s* $RXintx)* \s* (?: @ .*)?/ox,
16 INST_IO => qr/@.*/
17);
18
19sub init {
20 my ($this, $link_type, $dset, $choice) = @_;
21 unquote $choice;
22 dieContext("Unknown link type '$link_type', valid types are:",
23 sort keys %link_types) unless exists $link_types{$link_type};
24 $this->SUPER::init($dset, "DSET name");
25 $this->{LINK_TYPE} = $link_type;
26 $this->{CHOICE} = $choice;
27 return $this;
28}
29
30sub link_type {
31 return shift->{LINK_TYPE};
32}
33
34sub choice {
35 return shift->{CHOICE};
36}
37
38sub legal_addr {
39 my ($this, $addr) = @_;
40 my $rx = $link_types{$this->{LINK_TYPE}};
41 unquote $addr;
42 return $addr =~ m/^ $rx $/x;
43}
44
451;
046
=== added file 'src/tools/DBD/Driver.pm'
--- src/tools/DBD/Driver.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Driver.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,9 @@
1package DBD::Driver;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5sub init {
6 return shift->SUPER::init(shift, "driver entry table name");
7}
8
91;
010
=== added file 'src/tools/DBD/Function.pm'
--- src/tools/DBD/Function.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Function.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,10 @@
1package DBD::Function;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5sub init {
6 return shift->SUPER::init(shift, "function name");
7}
8
91;
10
011
=== added file 'src/tools/DBD/Menu.pm'
--- src/tools/DBD/Menu.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Menu.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,66 @@
1package DBD::Menu;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5sub init {
6 my ($this, $name) = @_;
7 $this->SUPER::init($name, "menu name");
8 $this->{CHOICE_LIST} = [];
9 $this->{CHOICE_INDEX} = {};
10 return $this;
11}
12
13sub add_choice {
14 my ($this, $name, $value) = @_;
15 $name = identifier($name, "Choice name");
16 unquote $value;
17 foreach $pair ($this->choices) {
18 dieContext("Duplicate choice name") if ($pair->[0] eq $name);
19 dieContext("Duplicate choice string") if ($pair->[1] eq $value);
20 }
21 push @{$this->{CHOICE_LIST}}, [$name, $value];
22 $this->{CHOICE_INDEX}->{$value} = $name;
23}
24
25sub choices {
26 return @{shift->{CHOICE_LIST}};
27}
28
29sub choice {
30 my ($this, $idx) = @_;
31 return $this->{CHOICE_LIST}[$idx];
32}
33
34sub legal_choice {
35 my ($this, $value) = @_;
36 unquote $value;
37 return exists $this->{CHOICE_INDEX}->{$value};
38}
39
40sub toDeclaration {
41 my $this = shift;
42 my $name = $this->name;
43 my @choices = map {
44 sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]);
45 } $this->choices;
46 return "typedef enum {\n" .
47 join(",\n", @choices) .
48 ",\n ${name}_NUM_CHOICES\n" .
49 "} $name;\n\n";
50}
51
52sub toDefinition {
53 my $this = shift;
54 my $name = $this->name;
55 my @strings = map {
56 "\t\"" . escapeCstring(@{$_}[1]) . "\""
57 } $this->choices;
58 return "static const char * const ${name}ChoiceStrings[] = {\n" .
59 join(",\n", @strings) . "\n};\n" .
60 "const dbMenu ${name}MenuMetaData = {\n" .
61 "\t\"" . escapeCstring($name) . "\",\n" .
62 "\t${name}_NUM_CHOICES,\n" .
63 "\t${name}ChoiceStrings\n};\n\n";
64}
65
661;
067
=== added file 'src/tools/DBD/Output.pm'
--- src/tools/DBD/Output.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Output.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,98 @@
1package DBD::Output;
2
3require Exporter;
4
5@ISA = qw(Exporter);
6@EXPORT = qw(&OutputDBD);
7
8use DBD;
9use DBD::Base;
10use DBD::Breaktable;
11use DBD::Device;
12use DBD::Driver;
13use DBD::Menu;
14use DBD::Recordtype;
15use DBD::Recfield;
16use DBD::Registrar;
17use DBD::Function;
18use DBD::Variable;
19
20sub OutputDBD {
21 my ($out, $dbd) = @_;
22 &OutputMenus($out, $dbd->menus);
23 &OutputRecordtypes($out, $dbd->recordtypes);
24 &OutputDrivers($out, $dbd->drivers);
25 &OutputRegistrars($out, $dbd->registrars);
26 &OutputFunctions($out, $dbd->functions);
27 &OutputVariables($out, $dbd->variables);
28 &OutputBreaktables($out, $dbd->breaktables);
29}
30
31sub OutputMenus {
32 my ($out, $menus) = @_;
33 while (my ($name, $menu) = each %{$menus}) {
34 printf $out "menu(%s) {\n", $name;
35 printf $out " choice(%s, \"%s\")\n", @{$_}
36 foreach $menu->choices;
37 print $out "}\n";
38 }
39}
40
41sub OutputRecordtypes {
42 my ($out, $recordtypes) = @_;
43 while (my ($name, $recordtype) = each %{$recordtypes}) {
44 printf $out "recordtype(%s) {\n", $name;
45 print $out " %$_\n"
46 foreach $recordtype->cdefs;
47 foreach $field ($recordtype->fields) {
48 printf $out " field(%s, %s) {\n",
49 $field->name, $field->dbf_type;
50 while (my ($attr, $val) = each %{$field->attributes}) {
51 $val = "\"$val\"" if $val !~ m/^[a-zA-Z0-9_\-+:.\[\]<>;]*$/;
52 printf $out " %s(%s)\n", $attr, $val;
53 }
54 print $out " }\n";
55 }
56 printf $out "}\n";
57 printf $out "device(%s, %s, %s, \"%s\")\n",
58 $name, $_->link_type, $_->name, $_->choice
59 foreach $recordtype->devices;
60 }
61}
62
63sub OutputDrivers {
64 my ($out, $drivers) = @_;
65 printf $out "driver(%s)\n", $_
66 foreach keys %{$drivers};
67}
68
69sub OutputRegistrars {
70 my ($out, $registrars) = @_;
71 printf $out "registrar(%s)\n", $_
72 foreach keys %{$registrars};
73}
74
75sub OutputFunctions {
76 my ($out, $functions) = @_;
77 printf $out "function(%s)\n", $_
78 foreach keys %{$functions};
79}
80
81sub OutputVariables {
82 my ($out, $variables) = @_;
83 while (my ($name, $variable) = each %{$variables}) {
84 printf $out "variable(%s, %s)\n", $name, $variable->var_type;
85 }
86}
87
88sub OutputBreaktables {
89 my ($out, $breaktables) = @_;
90 while (my ($name, $breaktable) = each %{$breaktables}) {
91 printf $out "breaktable(\"%s\") {\n", $name;
92 printf $out " point(%s, %s)\n", @{$_}
93 foreach $breaktable->points;
94 print $out "}\n";
95 }
96}
97
981;
099
=== added file 'src/tools/DBD/Parser.pm'
--- src/tools/DBD/Parser.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Parser.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,197 @@
1package DBD::Parser;
2require Exporter;
3
4@ISA = qw(Exporter);
5@EXPORT = qw(&ParseDBD);
6
7use DBD;
8use DBD::Base;
9use DBD::Breaktable;
10use DBD::Device;
11use DBD::Driver;
12use DBD::Menu;
13use DBD::Recordtype;
14use DBD::Recfield;
15use DBD::Registrar;
16use DBD::Function;
17use DBD::Variable;
18
19my $RXnam = qr/[a-zA-Z0-9_\-:.<>;]+/o;
20my $RXnum = qr/-? (?: \d+ ) | (?: \d* \. \d+ ) (?: [eE] [-+]? \d+ )?/ox;
21my $RXdqs = qr/" (?: [^"] | \\" )* "/ox;
22my $RXsqs = qr/' (?: [^'] | \\' )* '/ox;
23my $string = qr/ ( $RXnam | $RXnum | $RXdqs | $RXsqs ) /ox;
24
25our $debug=0;
26
27sub ParseDBD {
28 my $dbd = shift;
29 $_ = shift;
30 while (1) {
31 parseCommon();
32 if (m/\G menu \s* \( \s* $string \s* \) \s* \{/oxgc) {
33 print "Menu: $1\n" if $debug;
34 parse_menu($dbd, $1);
35 }
36 elsif (m/\G driver \s* \( \s* $string \s* \)/oxgc) {
37 print "Driver: $1\n" if $debug;
38 $dbd->add(DBD::Driver->new($1));
39 }
40 elsif (m/\G registrar \s* \( \s* $string \s* \)/oxgc) {
41 print "Registrar: $1\n" if $debug;
42 $dbd->add(DBD::Registrar->new($1));
43 }
44 elsif (m/\G function \s* \( \s* $string \s* \)/oxgc) {
45 print "Function: $1\n" if $debug;
46 $dbd->add(DBD::Function->new($1));
47 }
48 elsif (m/\G breaktable \s* \( \s* $string \s* \) \s* \{/oxgc) {
49 print "Breaktable: $1\n" if $debug;
50 parse_breaktable($dbd, $1);
51 }
52 elsif (m/\G recordtype \s* \( \s* $string \s* \) \s* \{/oxgc) {
53 print "Recordtype: $1\n" if $debug;
54 parse_recordtype($dbd, $1);
55 }
56 elsif (m/\G variable \s* \( \s* $string \s* \)/oxgc) {
57 print "Variable: $1\n" if $debug;
58 $dbd->add(DBD::Variable->new($1, 'int'));
59 }
60 elsif (m/\G variable \s* \( \s* $string \s* , \s* $string \s* \)/oxgc) {
61 print "Variable: $1, $2\n" if $debug;
62 $dbd->add(DBD::Variable->new($1, $2));
63 }
64 elsif (m/\G device \s* \( \s* $string \s* , \s* $string \s* ,
65 \s* $string \s* , \s*$string \s* \)/oxgc) {
66 print "Device: $1, $2, $3, $4\n" if $debug;
67 my $rtyp = $dbd->recordtype($1);
68 dieContext("Unknown record type '$1'") unless defined $rtyp;
69 $rtyp->add_device(DBD::Device->new($2, $3, $4));
70 } else {
71 last unless m/\G (.*) $/moxgc;
72 dieContext("Syntax error in '$1'");
73 }
74 }
75}
76
77sub parseCommon {
78 while (1) {
79 # Skip leading whitespace
80 m/\G \s* /oxgc;
81
82 if (m/\G \# /oxgc) {
83 if (m/\G \#!BEGIN\{ ( [^}]* ) \}!\#\# \n/oxgc) {
84 print "File-Begin: $1\n" if $debug;
85 pushContext("file '$1'");
86 }
87 elsif (m/\G \#!END\{ ( [^}]* ) \}!\#\# \n?/oxgc) {
88 print "File-End: $1\n" if $debug;
89 popContext("file '$1'");
90 }
91 else {
92 m/\G (.*) \n/oxgc;
93 print "Comment: $1\n" if $debug;
94 }
95 } else {
96 return;
97 }
98 }
99}
100
101sub parse_menu {
102 my ($dbd, $name) = @_;
103 pushContext("menu($name)");
104 my $menu = DBD::Menu->new($name);
105 while(1) {
106 parseCommon();
107 if (m/\G choice \s* \( \s* $string \s* , \s* $string \s* \)/oxgc) {
108 print " Menu-Choice: $1, $2\n" if $debug;
109 $menu->add_choice($1, $2);
110 }
111 elsif (m/\G \}/oxgc) {
112 print " Menu-End:\n" if $debug;
113 $dbd->add($menu);
114 popContext("menu($name)");
115 return;
116 } else {
117 m/\G (.*) $/moxgc or dieContext("Unexpected end of input");
118 dieContext("Syntax error in '$1'");
119 }
120 }
121}
122
123sub parse_breaktable {
124 my ($dbd, $name) = @_;
125 pushContext("breaktable($name)");
126 my $bt = DBD::Breaktable->new($name);
127 while(1) {
128 parseCommon();
129 if (m/\G point\s* \(\s* $string \s* , \s* $string \s* \)/oxgc) {
130 print " Breaktable-Point: $1, $2\n" if $debug;
131 $bt->add_point($1, $2);
132 }
133 elsif (m/\G $string \s* (?: , \s*)? $string (?: \s* ,)?/oxgc) {
134 print " Breaktable-Data: $1, $2\n" if $debug;
135 $bt->add_point($1, $2);
136 }
137 elsif (m/\G \}/oxgc) {
138 print " Breaktable-End:\n" if $debug;
139 $dbd->add($bt);
140 popContext("breaktable($name)");
141 return;
142 } else {
143 m/\G (.*) $/moxgc or dieContext("Unexpected end of input");
144 dieContext("Syntax error in '$1'");
145 }
146 }
147}
148
149sub parse_recordtype {
150 my ($dbd, $name) = @_;
151 pushContext("recordtype($name)");
152 my $rtyp = DBD::Recordtype->new($name);
153 while(1) {
154 parseCommon();
155 if (m/\G field \s* \( \s* $string \s* , \s* $string \s* \) \s* \{/oxgc) {
156 print " Recordtype-Field: $1, $2\n" if $debug;
157 parse_field($rtyp, $1, $2);
158 }
159 elsif (m/\G \}/oxgc) {
160 print " Recordtype-End:\n" if $debug;
161 $dbd->add($rtyp);
162 popContext("recordtype($name)");
163 return;
164 }
165 elsif (m/\G % (.*) \n/oxgc) {
166 print " Recordtype-Cdef: $1\n" if $debug;
167 $rtyp->add_cdef($1);
168 } else {
169 m/\G (.*) $/moxgc or dieContext("Unexpected end of input");
170 dieContext("Syntax error in '$1'");
171 }
172 }
173}
174
175sub parse_field {
176 my ($rtyp, $name, $field_type) = @_;
177 my $fld = DBD::Recfield->new($name, $field_type);
178 pushContext("field($name, $field_type)");
179 while(1) {
180 parseCommon();
181 if (m/\G (\w+) \s* \( \s* $string \s* \)/oxgc) {
182 print " Field-Attribute: $1, $2\n" if $debug;
183 $fld->add_attribute($1, $2);
184 }
185 elsif (m/\G \}/oxgc) {
186 print " Field-End:\n" if $debug;
187 $rtyp->add_field($fld);
188 popContext("field($name, $field_type)");
189 return;
190 } else {
191 m/\G (.*) $/moxgc or dieContext("Unexpected end of input");
192 dieContext("Syntax error in '$1'");
193 }
194 }
195}
196
1971;
0198
=== added file 'src/tools/DBD/Recfield.pm'
--- src/tools/DBD/Recfield.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Recfield.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,436 @@
1package DBD::Recfield;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5# The hash value is a regexp that matches all legal values of this field
6our %field_types = (
7 DBF_STRING => qr/.{0,40}/,
8 DBF_CHAR => $RXintx,
9 DBF_UCHAR => $RXuintx,
10 DBF_SHORT => $RXintx,
11 DBF_USHORT => $RXuintx,
12 DBF_LONG => $RXintx,
13 DBF_ULONG => $RXuintx,
14 DBF_FLOAT => $RXnum,
15 DBF_DOUBLE => $RXnum,
16 DBF_ENUM => qr/.*/,
17 DBF_MENU => qr/.*/,
18 DBF_DEVICE => qr/.*/,
19 DBF_INLINK => qr/.*/,
20 DBF_OUTLINK => qr/.*/,
21 DBF_FWDLINK => qr/.*/,
22 DBF_NOACCESS => qr//
23);
24
25# The hash value is a regexp that matches all legal values of this attribute
26our %field_attrs = (
27 asl => qr/^ASL[01]$/,
28 initial => qr/^.*$/,
29 promptgroup => qr/^GUI_\w+$/,
30 prompt => qr/^.*$/,
31 special => qr/^(?:SPC_\w+|\d{3,})$/,
32 pp => qr/^(?:TRUE|FALSE)$/,
33 interest => qr/^\d+$/,
34 base => qr/^(?:DECIMAL|HEX)$/,
35 size => qr/^\d+$/,
36 extra => qr/^.*$/,
37 menu => qr/^$RXident$/o
38);
39
40sub new {
41 my ($class, $name, $type) = @_;
42 dieContext("Illegal field type '$type', valid field types are:",
43 sort keys %field_types) unless exists $field_types{$type};
44 my $this = {};
45 bless $this, "${class}::${type}";
46 return $this->init($name, $type);
47}
48
49sub init {
50 my ($this, $name, $type) = @_;
51 unquote $type;
52 $this->SUPER::init($name, "record field name");
53 dieContext("Illegal field type '$type', valid field types are:",
54 sort keys %field_types) unless exists $field_types{$type};
55 $this->{DBF_TYPE} = $type;
56 $this->{ATTR_INDEX} = {};
57 return $this;
58}
59
60sub dbf_type {
61 return shift->{DBF_TYPE};
62}
63
64sub set_number {
65 my ($this, $number) = @_;
66 $this->{NUMBER} = $number;
67}
68
69sub number {
70 return shift->{NUMBER};
71}
72
73sub add_attribute {
74 my ($this, $attr, $value) = @_;
75 unquote $value;
76 my $match = $field_attrs{$attr};
77 dieContext("Unknown field attribute '$1', valid attributes are:",
78 sort keys %field_attrs)
79 unless defined $match;
80 dieContext("Bad value '$value' for field '$attr' attribute")
81 unless $value =~ m/$match/;
82 $this->{ATTR_INDEX}->{$attr} = $value;
83}
84
85sub attributes {
86 return shift->{ATTR_INDEX};
87}
88
89sub attribute {
90 my ($this, $attr) = @_;
91 return $this->attributes->{$attr};
92}
93
94sub check_valid {
95 my ($this) = @_;
96 my $name = $this->name;
97 my $default = $this->attribute("initial");
98 dieContext("Default value '$default' is invalid for field '$name'")
99 if (defined($default) and !$this->legal_value($default));
100}
101
102# The C structure member name is usually the field name converted to
103# lower-case. However if that is a reserved word, use the original.
104sub C_name {
105 my ($this) = @_;
106 my $name = lc $this->name;
107 $name = $this->name
108 if is_reserved($name);
109 return $name;
110}
111
112sub toDeclaration {
113 my ($this, $ctype) = @_;
114 my $name = $this->C_name;
115 my $result = sprintf " %-19s %-12s", $ctype, "$name;";
116 my $prompt = $this->attribute('prompt');
117 $result .= "/* $prompt */" if defined $prompt;
118 return $result;
119}
120
121
122################################################################################
123
124package DBD::Recfield::DBF_STRING;
125
126use DBD::Base;
127@ISA = qw(DBD::Recfield);
128
129sub legal_value {
130 my ($this, $value) = @_;
131 return (length $value < $this->attribute('size'));
132 # NB - we use '<' to allow space for the terminating nil byte
133}
134
135sub check_valid {
136 my ($this) = @_;
137 dieContext("Size missing for DBF_STRING field '$name'")
138 unless exists $this->attributes->{'size'};
139 $this->SUPER::check_valid;
140}
141
142sub toDeclaration {
143 my ($this) = @_;
144 my $name = lc $this->name;
145 my $size = $this->attribute('size');
146 my $result = sprintf " %-19s %-12s", 'char', "${name}[${size}];";
147 my $prompt = $this->attribute('prompt');
148 $result .= "/* $prompt */" if defined $prompt;
149 return $result;
150}
151
152
153################################################################################
154
155package DBD::Recfield::DBF_CHAR;
156
157use DBD::Base;
158@ISA = qw(DBD::Recfield);
159
160sub legal_value {
161 my ($this, $value) = @_;
162 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
163 return ($value =~ m/^ $RXint $/x and
164 $value >= -128 and
165 $value <= 127);
166}
167
168sub toDeclaration {
169 return shift->SUPER::toDeclaration("epicsInt8");
170}
171
172
173################################################################################
174
175package DBD::Recfield::DBF_UCHAR;
176
177use DBD::Base;
178@ISA = qw(DBD::Recfield);
179
180sub legal_value {
181 my ($this, $value) = @_;
182 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
183 return ($value =~ m/^ $RXuint $/x and
184 $value >= 0 and
185 $value <= 255);
186}
187
188sub toDeclaration {
189 return shift->SUPER::toDeclaration("epicsUInt8");
190}
191
192
193################################################################################
194
195package DBD::Recfield::DBF_SHORT;
196
197use DBD::Base;
198@ISA = qw(DBD::Recfield);
199
200sub legal_value {
201 my ($this, $value) = @_;
202 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
203 return ($value =~ m/^ $RXint $/x and
204 $value >= -32768 and
205 $value <= 32767);
206}
207
208sub toDeclaration {
209 return shift->SUPER::toDeclaration("epicsInt16");
210}
211
212
213################################################################################
214
215package DBD::Recfield::DBF_USHORT;
216
217use DBD::Base;
218@ISA = qw(DBD::Recfield);
219
220sub legal_value {
221 my ($this, $value) = @_;
222 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
223 return ($value =~ m/^ $RXuint $/x and
224 $value >= 0 and
225 $value <= 65535);
226}
227
228sub toDeclaration {
229 return shift->SUPER::toDeclaration("epicsUInt16");
230}
231
232
233################################################################################
234
235package DBD::Recfield::DBF_LONG;
236
237use DBD::Base;
238@ISA = qw(DBD::Recfield);
239
240sub legal_value {
241 my ($this, $value) = @_;
242 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
243 return ($value =~ m/^ $RXint $/x);
244}
245
246sub toDeclaration {
247 return shift->SUPER::toDeclaration("epicsInt32");
248}
249
250
251################################################################################
252
253package DBD::Recfield::DBF_ULONG;
254
255use DBD::Base;
256@ISA = qw(DBD::Recfield);
257
258sub legal_value {
259 my ($this, $value) = @_;
260 $value =~ s/^ ( $RXhex | $RXoct ) $/ oct($1) /xe;
261 return ($value =~ m/^ $RXuint $/x and
262 $value >= 0);
263}
264
265sub toDeclaration {
266 return shift->SUPER::toDeclaration("epicsUInt32");
267}
268
269
270################################################################################
271
272package DBD::Recfield::DBF_FLOAT;
273
274use DBD::Base;
275@ISA = qw(DBD::Recfield);
276
277sub legal_value {
278 my ($this, $value) = @_;
279 return ($value =~ m/^ $RXnum $/x);
280}
281
282sub toDeclaration {
283 return shift->SUPER::toDeclaration("epicsFloat32");
284}
285
286
287################################################################################
288
289package DBD::Recfield::DBF_DOUBLE;
290
291use DBD::Base;
292@ISA = qw(DBD::Recfield);
293
294sub legal_value {
295 my ($this, $value) = @_;
296 return ($value =~ m/^ $RXnum $/x);
297}
298
299sub toDeclaration {
300 return shift->SUPER::toDeclaration("epicsFloat64");
301}
302
303
304################################################################################
305
306package DBD::Recfield::DBF_ENUM;
307
308use DBD::Base;
309@ISA = qw(DBD::Recfield);
310
311sub legal_value {
312 return 1;
313}
314
315sub toDeclaration {
316 return shift->SUPER::toDeclaration("epicsEnum16");
317}
318
319
320################################################################################
321
322package DBD::Recfield::DBF_MENU;
323
324use DBD::Base;
325@ISA = qw(DBD::Recfield);
326
327sub legal_value {
328 # FIXME: If we know the menu name and the menu exists, check further
329 return 1;
330}
331
332sub check_valid {
333 my ($this) = @_;
334 dieContext("Menu name missing for DBF_MENU field '$name'")
335 unless defined($this->attribute("menu"));
336 $this->SUPER::check_valid;
337}
338
339sub toDeclaration {
340 return shift->SUPER::toDeclaration("epicsEnum16");
341}
342
343
344################################################################################
345
346package DBD::Recfield::DBF_DEVICE;
347
348use DBD::Base;
349@ISA = qw(DBD::Recfield);
350
351sub legal_value {
352 return 1;
353}
354
355sub toDeclaration {
356 return shift->SUPER::toDeclaration("epicsEnum16");
357}
358
359
360################################################################################
361
362package DBD::Recfield::DBF_INLINK;
363
364use DBD::Base;
365@ISA = qw(DBD::Recfield);
366
367sub legal_value {
368 return 1;
369}
370
371sub toDeclaration {
372 return shift->SUPER::toDeclaration("DBLINK");
373}
374
375
376################################################################################
377
378package DBD::Recfield::DBF_OUTLINK;
379
380use DBD::Base;
381@ISA = qw(DBD::Recfield);
382
383sub legal_value {
384 return 1;
385}
386
387sub toDeclaration {
388 return shift->SUPER::toDeclaration("DBLINK");
389}
390
391
392################################################################################
393
394package DBD::Recfield::DBF_FWDLINK;
395
396use DBD::Base;
397@ISA = qw(DBD::Recfield);
398
399sub legal_value {
400 return 1;
401}
402
403sub toDeclaration {
404 return shift->SUPER::toDeclaration("DBLINK");
405}
406
407
408################################################################################
409
410package DBD::Recfield::DBF_NOACCESS;
411
412use DBD::Base;
413@ISA = qw(DBD::Recfield);
414
415sub legal_value {
416 my ($this, $value) = @_;
417 return ($value eq '');
418}
419
420sub check_valid {
421 my ($this) = @_;
422 dieContext("Type information missing for DBF_NOACCESS field '$name'")
423 unless defined($this->attribute("extra"));
424 $this->SUPER::check_valid;
425}
426
427sub toDeclaration {
428 my ($this) = @_;
429 my $extra = $this->attribute('extra');
430 my $result = sprintf " %-31s ", "$extra;";
431 my $prompt = $this->attribute('prompt');
432 $result .= "/* $prompt */" if defined $prompt;
433 return $result;
434}
435
4361;
0437
=== added file 'src/tools/DBD/Recordtype.pm'
--- src/tools/DBD/Recordtype.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Recordtype.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,100 @@
1package DBD::Recordtype;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5use Carp;
6
7sub init {
8 my $this = shift;
9 $this->SUPER::init(@_);
10 $this->{FIELD_LIST} = [];
11 $this->{FIELD_INDEX} = {};
12 $this->{DEVICE_LIST} = [];
13 $this->{DEVICE_INDEX} = {};
14 $this->{CDEFS} = [];
15 return $this;
16}
17
18sub add_field {
19 my ($this, $field) = @_;
20 confess "Not a DBD::Recfield" unless $field->isa('DBD::Recfield');
21 my $field_name = $field->name;
22 dieContext("Duplicate field name '$field_name'")
23 if exists $this->{FIELD_INDEX}->{$field_name};
24 $field->check_valid;
25 $field->set_number(scalar @{$this->{FIELD_LIST}});
26 push @{$this->{FIELD_LIST}}, $field;
27 $this->{FIELD_INDEX}->{$field_name} = $field;
28}
29
30sub fields {
31 return @{shift->{FIELD_LIST}};
32}
33
34sub field_names { # In their original order...
35 my $this = shift;
36 my @names = ();
37 foreach ($this->fields) {
38 push @names, $_->name
39 }
40 return @names;
41}
42
43sub field {
44 my ($this, $field_name) = @_;
45 return $this->{FIELD_INDEX}->{$field_name};
46}
47
48sub add_device {
49 my ($this, $device) = @_;
50 confess "Not a DBD::Device" unless $device->isa('DBD::Device');
51 my $choice = $device->choice;
52 if (exists $this->{DEVICE_INDEX}->{$choice}) {
53 my @warning = ("Duplicate device type '$choice'");
54 my $old = $this->{DEVICE_INDEX}->{$choice};
55 push @warning, "Link types differ"
56 if ($old->link_type ne $device->link_type);
57 push @warning, "DSETs differ"
58 if ($old->name ne $device->name);
59 warnContext(@warning);
60 return;
61 }
62 push @{$this->{DEVICE_LIST}}, $device;
63 $this->{DEVICE_INDEX}->{$choice} = $device;
64}
65
66sub devices {
67 return @{shift->{DEVICE_LIST}};
68}
69
70sub device {
71 my ($this, $choice) = @_;
72 return $this->{DEVICE_INDEX}->{$choice};
73}
74
75sub add_cdef {
76 my ($this, $cdef) = @_;
77 push @{$this->{CDEFS}}, $cdef;
78}
79
80sub cdefs {
81 return @{shift->{CDEFS}};
82}
83
84sub toCdefs {
85 return join("\n", shift->cdefs) . "\n\n";
86}
87
88sub toDeclaration {
89 my $this = shift;
90 my @fields = map {
91 $_->toDeclaration
92 } $this->fields;
93 my $name = $this->name;
94 $name .= "Record" unless $name eq "dbCommon";
95 return "typedef struct $name {\n" .
96 join("\n", @fields) .
97 "\n} $name;\n\n";
98}
99
1001;
0101
=== added file 'src/tools/DBD/Registrar.pm'
--- src/tools/DBD/Registrar.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Registrar.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,11 @@
1package DBD::Registrar;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5sub init {
6 return shift->SUPER::init(shift, "registrar function name");
7}
8
9
101;
11
012
=== added file 'src/tools/DBD/Variable.pm'
--- src/tools/DBD/Variable.pm 1970-01-01 00:00:00 +0000
+++ src/tools/DBD/Variable.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,36 @@
1package DBD::Variable;
2use DBD::Base;
3@ISA = qw(DBD::Base);
4
5my %valid_types = (
6 # C type name => corresponding iocshArg type identifier
7 int => 'iocshArgInt',
8 double => 'iocshArgDouble'
9);
10
11sub init {
12 my ($this, $name, $type) = @_;
13 if (defined $type) {
14 unquote $type;
15 } else {
16 $type = "int";
17 }
18 exists $valid_types{$type} or
19 dieContext("Unknown variable type '$type', valid types are:",
20 sort keys %valid_types);
21 $this->SUPER::init($name, "variable name");
22 $this->{VAR_TYPE} = $type;
23 return $this;
24}
25
26sub var_type {
27 my $this = shift;
28 return $this->{VAR_TYPE};
29}
30
31sub iocshArg_type {
32 my $this = shift;
33 return $valid_types{$this->{VAR_TYPE}};
34}
35
361;
037
=== added file 'src/tools/EPICS/Readfile.pm'
--- src/tools/EPICS/Readfile.pm 1970-01-01 00:00:00 +0000
+++ src/tools/EPICS/Readfile.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,101 @@
1#*************************************************************************
2# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
3# National Laboratory.
4# EPICS BASE is distributed subject to a Software License Agreement found
5# in file LICENSE that is included with this distribution.
6#*************************************************************************
7
8# $Id$
9
10package EPICS::Readfile;
11require 5.000;
12require Exporter;
13
14use EPICS::macLib;
15
16@ISA = qw(Exporter);
17@EXPORT = qw(@inputfiles &Readfile);
18
19our $debug=0;
20our @inputfiles;
21
22sub slurp {
23 my ($FILE, $Rpath) = @_;
24 my @path = @{$Rpath};
25 print "slurp($FILE):\n" if $debug;
26 if ($FILE !~ m[/]) {
27 foreach $dir (@path) {
28 print " trying $dir/$FILE\n" if $debug;
29 if (-r "$dir/$FILE") {
30 $FILE = "$dir/$FILE";
31 last;
32 }
33 }
34 die "Can't find file '$FILE'\n" unless -r $FILE;
35 }
36 print " opening $FILE\n" if $debug;
37 open FILE, "<$FILE" or die "Can't open $FILE: $!\n";
38 push @inputfiles, $FILE;
39 my @lines = ("##!BEGIN{$FILE}!##\n");
40 # Consider replacing these markers with C pre-processor linemarkers.
41 # See 'info cpp' * Preprocessor Output:: for details.
42 push @lines, <FILE>;
43 push @lines, "##!END{$FILE}!##\n";
44 close FILE or die "Error closing $FILE: $!\n";
45 print " read ", scalar @lines, " lines\n" if $debug;
46 return join '', @lines;
47}
48
49sub expandMacros {
50 my ($macros, $input) = @_;
51 return $input unless $macros;
52 return $macros->expandString($input);
53}
54
55sub splitPath {
56 my ($path) = @_;
57 my (@path) = split /[:;]/, $path;
58 grep s/^$/./, @path;
59 return @path;
60}
61
62my $RXstr = qr/ " (?: [^"] | \\" )* "/ox;
63my $RXnam = qr/[a-zA-Z0-9_\-:.[\]<>;]+/o;
64my $string = qr/ ( $RXnam | $RXstr ) /ox;
65
66sub unquote {
67 my ($s) = @_;
68 $s =~ s/^"(.*)"$/$1/o;
69 return $s;
70}
71
72sub Readfile {
73 my ($file, $macros, $Rpath) = @_;
74 print "Readfile($file)\n" if $debug;
75 my $input = &expandMacros($macros, &slurp($file, $Rpath));
76 my @input = split /\n/, $input;
77 my @output;
78 foreach (@input) {
79 if (m/^ \s* include \s+ $string /ox) {
80 $arg = &unquote($1);
81 print " include $arg\n" if $debug;
82 push @output, "##! include \"$arg\"";
83 push @output, &Readfile($arg, $macros, $Rpath);
84 } elsif (m/^ \s* addpath \s+ $string /ox) {
85 $arg = &unquote($1);
86 print " addpath $arg\n" if $debug;
87 push @output, "##! addpath \"$arg\"";
88 push @{$Rpath}, &splitPath($arg);
89 } elsif (m/^ \s* path \s+ $string /ox) {
90 $arg = &unquote($1);
91 print " path $arg\n" if $debug;
92 push @output, "##! path \"$arg\"";
93 @{$Rpath} = &splitPath($arg);
94 } else {
95 push @output, $_;
96 }
97 }
98 return join "\n", @output;
99}
100
1011;
0102
=== added file 'src/tools/EPICS/macLib.pm'
--- src/tools/EPICS/macLib.pm 1970-01-01 00:00:00 +0000
+++ src/tools/EPICS/macLib.pm 2012-04-02 20:38:19 +0000
@@ -0,0 +1,251 @@
1#*************************************************************************
2# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
3# National Laboratory.
4# EPICS BASE is distributed subject to a Software License Agreement found
5# in file LICENSE that is included with this distribution.
6#*************************************************************************
7
8# $Id$
9
10package EPICS::macLib::entry;
11
12sub new ($$) {
13 my $class = shift;
14 my $this = {
15 name => shift,
16 type => shift,
17 raw => '',
18 val => '',
19 visited => 0,
20 error => 0,
21 };
22 bless $this, $class;
23 return $this;
24}
25
26sub report ($) {
27 my ($this) = @_;
28 return unless defined $this->{raw};
29 printf "%1s %-16s %-16s %s\n",
30 ($this->{error} ? '*' : ' '), $this->{name}, $this->{raw}, $this->{val};
31}
32
33
34package EPICS::macLib;
35
36use Carp;
37
38sub new ($@) {
39 my $proto = shift;
40 my $class = ref($proto) || $proto;
41 my $this = {
42 dirty => 0,
43 noWarn => 0,
44 macros => [{}], # [0] is current scope, [1] is parent etc.
45 };
46 bless $this, $class;
47 $this->installList(@_);
48 return $this;
49}
50
51sub installList ($@) {
52 # Argument is a list of strings which are arguments to installMacros
53 my $this = shift;
54 while (@_) {
55 $this->installMacros(shift);
56 }
57}
58
59sub installMacros ($$) {
60 # Argument is a string: a=1,b="2",c,d='hello'
61 my $this = shift;
62 $_ = shift;
63 until (defined pos($_) and pos($_) == length($_)) {
64 m/\G \s* /xgc; # Skip whitespace
65 if (m/\G ( [A-Za-z0-9_-]+ ) \s* /xgc) {
66 my ($name, $val) = ($1);
67 if (m/\G = \s* /xgc) {
68 # The value follows, handle quotes and escapes
69 until (pos($_) == length($_)) {
70 if (m/\G , /xgc) { last; }
71 elsif (m/\G ' ( ( [^'] | \\ ' )* ) ' /xgc) { $val .= $1; }
72 elsif (m/\G " ( ( [^"] | \\ " )* ) " /xgc) { $val .= $1; }
73 elsif (m/\G \\ ( . ) /xgc) { $val .= $1; }
74 elsif (m/\G ( . ) /xgc) { $val .= $1; }
75 else { die "How did I get here?"; }
76 }
77 $this->putValue($name, $val);
78 } elsif (m/\G , /xgc or (pos($_) == length($_))) {
79 $this->putValue($name, undef);
80 } else {
81 warn "How did I get here?";
82 }
83 } elsif (m/\G ( .* )/xgc) {
84 croak "Can't find a macro definition in '$1'";
85 } else {
86 last;
87 }
88 }
89}
90
91sub putValue ($$$) {
92 my ($this, $name, $raw) = @_;
93 if (exists $this->{macros}[0]{$name}) {
94 if (!defined $raw) {
95 delete $this->{macros}[0]{$name};
96 } else {
97 $this->{macros}[0]{$name}{raw} = $raw;
98 }
99 } else {
100 my $entry = EPICS::macLib::entry->new($name, 'macro');
101 $entry->{raw} = $raw;
102 $this->{macros}[0]{$name} = $entry;
103 }
104 $this->{dirty} = 1;
105}
106
107sub pushScope ($) {
108 my ($this) = @_;
109 unshift @{$this->{macros}}, {};
110}
111
112sub popScope ($) {
113 my ($this) = @_;
114 shift @{$this->{macros}};
115}
116
117sub suppressWarning($$) {
118 my ($this, $suppress) = @_;
119 $this->{noWarn} = $suppress;
120}
121
122sub expandString($$) {
123 my ($this, $src) = @_;
124 $this->_expand;
125 my $entry = EPICS::macLib::entry->new($src, 'string');
126 my $result = $this->_translate($entry, 0, $src);
127 return $result unless $entry->{error};
128 return $this->{noWarn} ? $result : undef;
129}
130
131sub reportMacros ($) {
132 my ($this) = @_;
133 $this->_expand;
134 print "Macro report\n============\n";
135 foreach my $scope (@{$this->{macros}}) {
136 foreach my $name (keys %{$scope}) {
137 my $entry = $scope->{$name};
138 $entry->report;
139 }
140 } continue {
141 print " -- scope ends --\n";
142 }
143}
144
145
146# Private routines, not intended for public use
147
148sub _expand ($) {
149 my ($this) = @_;
150 return unless $this->{dirty};
151 foreach my $scope (@{$this->{macros}}) {
152 foreach my $name (keys %{$scope}) {
153 my $entry = $scope->{$name};
154 $entry->{val} = $this->_translate($entry, 1, $entry->{raw});
155 }
156 }
157 $this->{dirty} = 0;
158}
159
160sub _lookup ($$$$$) {
161 my ($this, $name) = @_;
162 foreach my $scope (@{$this->{macros}}) {
163 if (exists $scope->{$name}) {
164 return undef # Macro marked as deleted
165 unless defined $scope->{$name}{raw};
166 return $scope->{$name};
167 }
168 }
169 return undef;
170}
171
172sub _translate ($$$$) {
173 my ($this, $entry, $level, $str) = @_;
174 return $this->_trans($entry, $level, '', \$str);
175}
176
177sub _trans ($$$$$) {
178 my ($this, $entry, $level, $term, $R) = @_;
179 return $$R
180 if (!defined $$R or
181 $$R =~ m/\A [^\$]* \Z/x); # Short-circuit if no macros
182 my $quote = 0;
183 my $val;
184 until (defined pos($$R) and pos($$R) == length($$R)) {
185 if ($term and ($$R =~ m/\G (?= [$term] ) /xgc)) {
186 last;
187 }
188 if ($$R =~ m/\G \$ ( [({] ) /xgc) {
189 my $macEnd = $1;
190 $macEnd =~ tr/({/)}/;
191 my $name2 = $this->_trans($entry, $level+1, "=$macEnd", $R);
192 my $entry2 = $this->_lookup($name2);
193 if (!defined $entry2) { # Macro not found
194 if ($$R =~ m/\G = /xgc) { # Use default value given
195 $val .= $this->_trans($entry, $level+1, $macEnd, $R);
196 } else {
197 unless ($this->{noWarn}) {
198 $entry->{error} = 1;
199 printf STDERR "macLib: macro '%s' is undefined (expanding %s '%s')\n",
200 $name2, $entry->{type}, $entry->{name};
201 }
202 $val .= "\$($name2)";
203 }
204 $$R =~ m/\G [$macEnd] /xgc; # Discard close bracket
205 } else { # Macro found
206 if ($entry2->{visited}) {
207 $entry->{error} = 1;
208 printf STDERR "macLib: %s '%s' is recursive (expanding %s '%s')\n",
209 $entry->{type}, $entry->{name}, $entry2->{type}, $entry2->{name};
210 $val .= "\$($name)";
211 } else {
212 if ($$R =~ m/\G = /xgc) { # Discard default value
213 local $this->{noWarn} = 1; # Temporarily kill warnings
214 $this->_trans($entry, $level+1, $macEnd, $R);
215 }
216 $$R =~ m/\G [$macEnd] /xgc; # Discard close bracket
217 if ($this->{dirty}) { # Translate raw value
218 $entry2->{visited} = 1;
219 $val .= $this->_trans($entry, $level+1, '', \$entry2->{raw});
220 $entry2->{visited} = 0;
221 } else {
222 $val .= $entry2->{val}; # Here's one I made earlier...
223 }
224 }
225 }
226 } elsif ($level > 0) { # Discard quotes and escapes
227 if ($quote and $$R =~ m/\G $quote /xgc) {
228 $quote = 0;
229 } elsif ($$R =~ m/\G ( ['"] ) /xgc) {
230 $quote = $1;
231 } elsif ($$R =~ m/\G \\? ( . ) /xgc) {
232 $val .= $1;
233 } else {
234 warn "How did I get here? level=$level";
235 }
236 } else { # Level 0
237 if ($$R =~ m/\G \\ ( . ) /xgc) {
238 $val .= "\\$1";
239 } elsif ($$R =~ m/\G ( [^\\\$'")}]* ) /xgc) {
240 $val .= $1;
241 } elsif ($$R =~ m/\G ( . ) /xgc) {
242 $val .= $1;
243 } else {
244 warn "How did I get here? level=$level";
245 }
246 }
247 }
248 return $val;
249}
250
2511;
0252
=== modified file 'src/tools/Makefile'
--- src/tools/Makefile 2008-09-23 22:13:52 +0000
+++ src/tools/Makefile 2012-04-02 20:38:19 +0000
@@ -1,5 +1,5 @@
1#*************************************************************************1#*************************************************************************
2# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne2# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
3# National Laboratory.3# National Laboratory.
4# EPICS BASE is distributed subject to a Software License Agreement found4# EPICS BASE is distributed subject to a Software License Agreement found
5# in file LICENSE that is included with this distribution. 5# in file LICENSE that is included with this distribution.
@@ -14,7 +14,23 @@
14PERL_MODULES += EPICS/Copy.pm14PERL_MODULES += EPICS/Copy.pm
15PERL_MODULES += EPICS/Path.pm15PERL_MODULES += EPICS/Path.pm
16PERL_MODULES += EPICS/Release.pm16PERL_MODULES += EPICS/Release.pm
17PERL_MODULES += EPICS/Readfile.pm
17PERL_MODULES += EPICS/Getopts.pm18PERL_MODULES += EPICS/Getopts.pm
19PERL_MODULES += EPICS/macLib.pm
20
21PERL_MODULES += DBD.pm
22PERL_MODULES += DBD/Base.pm
23PERL_MODULES += DBD/Breaktable.pm
24PERL_MODULES += DBD/Device.pm
25PERL_MODULES += DBD/Driver.pm
26PERL_MODULES += DBD/Function.pm
27PERL_MODULES += DBD/Menu.pm
28PERL_MODULES += DBD/Output.pm
29PERL_MODULES += DBD/Parser.pm
30PERL_MODULES += DBD/Recfield.pm
31PERL_MODULES += DBD/Recordtype.pm
32PERL_MODULES += DBD/Registrar.pm
33PERL_MODULES += DBD/Variable.pm
1834
19PERL_SCRIPTS += convertRelease.pl35PERL_SCRIPTS += convertRelease.pl
20PERL_SCRIPTS += cvsclean.pl36PERL_SCRIPTS += cvsclean.pl
@@ -32,5 +48,10 @@
32PERL_SCRIPTS += replaceVAR.pl48PERL_SCRIPTS += replaceVAR.pl
33PERL_SCRIPTS += useManifestTool.pl49PERL_SCRIPTS += useManifestTool.pl
3450
51PERL_SCRIPTS += dbdToMenuH.pl
52PERL_SCRIPTS += dbdToRecordtypeH.pl
53PERL_SCRIPTS += dbdExpand.pl
54PERL_SCRIPTS += dbdToHtml.pl
55
35include $(TOP)/configure/RULES56include $(TOP)/configure/RULES
36 57
3758
=== added file 'src/tools/dbdExpand.pl'
--- src/tools/dbdExpand.pl 1970-01-01 00:00:00 +0000
+++ src/tools/dbdExpand.pl 2012-04-02 20:38:19 +0000
@@ -0,0 +1,53 @@
1#!/usr/bin/perl
2
3#*************************************************************************
4# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.
6# EPICS BASE is distributed subject to a Software License Agreement found
7# in file LICENSE that is included with this distribution.
8#*************************************************************************
9
10# $Id$
11
12use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";
14
15use DBD;
16use DBD::Parser;
17use DBD::Output;
18use EPICS::Getopts;
19use EPICS::Readfile;
20use EPICS::macLib;
21
22getopts('DI@S@o:') or
23 die "Usage: dbdExpand [-D] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ...";
24
25my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
26my $macros = EPICS::macLib->new(@opt_S);
27my $dbd = DBD->new();
28
29while (@ARGV) {
30 &ParseDBD($dbd, &Readfile(shift @ARGV, $macros, \@opt_I));
31}
32
33if ($opt_D) { # Output dependencies only
34 my %filecount;
35 my @uniqfiles = grep { not $filecount{$_}++ } @inputfiles;
36 print "$opt_o: ", join(" \\\n ", @uniqfiles), "\n\n";
37 print map { "$_:\n" } @uniqfiles;
38 exit 0;
39}
40
41my $out;
42if ($opt_o) {
43 open $out, '>', $opt_o or die "Can't create $opt_o: $!\n";
44} else {
45 $out = STDOUT;
46}
47
48&OutputDBD($out, $dbd);
49
50if ($opt_o) {
51 close $out or die "Closing $opt_o failed: $!\n";
52}
53exit 0;
054
=== added file 'src/tools/dbdReport.pl'
--- src/tools/dbdReport.pl 1970-01-01 00:00:00 +0000
+++ src/tools/dbdReport.pl 2012-04-02 20:38:19 +0000
@@ -0,0 +1,64 @@
1#!/usr/bin/perl
2
3#*************************************************************************
4# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.
6# EPICS BASE is distributed subject to a Software License Agreement found
7# in file LICENSE that is included with this distribution.
8#*************************************************************************
9
10# $Id$
11
12use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";
14
15use DBD;
16use DBD::Parser;
17use EPICS::Getopts;
18use EPICS::macLib;
19use EPICS::Readfile;
20use Text::Wrap;
21
22#$EPICS::Readfile::debug = 1;
23#$DBD::Parser::debug = 1;
24
25getopts('I@S@') or die usage();
26
27sub usage() {
28 "Usage: dbdReport [-I dir:dir2] [-S macro=val,...] file.dbd ...";
29}
30
31my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
32my $macros = EPICS::macLib->new(@opt_S);
33my $dbd = DBD->new();
34
35&ParseDBD($dbd, &Readfile(shift @ARGV, $macros, \@opt_I));
36
37$Text::Wrap::columns = 75;
38
39my @menus = sort keys %{$dbd->menus};
40print wrap("Menus:\t", "\t", join(', ', @menus)), "\n"
41 if @menus;
42my @drivers = sort keys %{$dbd->drivers};
43print wrap("Drivers: ", "\t", join(', ', @drivers)), "\n"
44 if @drivers;
45my @variables = sort keys %{$dbd->variables};
46print wrap("Variables: ", "\t", join(', ', @variables)), "\n"
47 if @variables;
48my @registrars = sort keys %{$dbd->registrars};
49print wrap("Registrars: ", "\t", join(', ', @registrars)), "\n"
50 if @registrars;
51my @breaktables = sort keys %{$dbd->breaktables};
52print wrap("Breaktables: ", "\t", join(', ', @breaktables)), "\n"
53 if @breaktables;
54my %recordtypes = %{$dbd->recordtypes};
55if (%recordtypes) {
56 @rtypes = sort keys %recordtypes;
57 print wrap("Recordtypes: ", "\t", join(', ', @rtypes)), "\n";
58 foreach my $rtyp (@rtypes) {
59 my @devices = $recordtypes{$rtyp}->devices;
60 print wrap("Devices($rtyp): ", "\t",
61 join(', ', map {$_->choice} @devices)), "\n"
62 if @devices;
63 }
64}
065
=== added file 'src/tools/dbdToHtml.pl'
--- src/tools/dbdToHtml.pl 1970-01-01 00:00:00 +0000
+++ src/tools/dbdToHtml.pl 2012-04-02 20:38:19 +0000
@@ -0,0 +1,252 @@
1#!/usr/bin/perl
2
3#*************************************************************************
4# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.
6# EPICS BASE is distributed subject to a Software License Agreement found
7# in file LICENSE that is included with this distribution.
8#*************************************************************************
9
10# $Id$
11
12use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";
14
15use DBD;
16use DBD::Parser;
17use EPICS::Getopts;
18use EPICS::macLib;
19use EPICS::Readfile;
20
21my $tool = 'dbdToHtml';
22getopts('DI@o:') or
23 die "Usage: $tool [-D] [-I dir] [-o xRecord.html] xRecord.dbd\n";
24
25my @path = map { split /[:;]/ } @opt_I;
26my $dbd = DBD->new();
27
28my $infile = shift @ARGV;
29$infile =~ m/\.dbd$/ or
30 die "$tool: Input file '$infile' must have '.dbd' extension\n";
31
32&ParseDBD($dbd, &Readfile($infile, 0, \@opt_I));
33
34if ($opt_D) { # Output dependencies only
35 my %filecount;
36 my @uniqfiles = grep { not $filecount{$_}++ } @inputfiles;
37 print "$opt_o: ", join(" \\\n ", @uniqfiles), "\n\n";
38 print map { "$_:\n" } @uniqfiles;
39 exit 0;
40}
41
42my $out;
43if ($opt_o) {
44 $out = $opt_o;
45} else {
46 ($out = $infile) =~ s/\.dbd$/.html/;
47 $out =~ s/^.*\///;
48 $out =~ s/dbCommonRecord/dbCommon/;
49}
50open $out, '>', $opt_o or die "Can't create $opt_o: $!\n";
51
52print $out "<h1>$infile</h1>\n";
53
54my $rtypes = $dbd->recordtypes;
55
56my ($rn, $rtyp) = each %{$rtypes};
57print $out "<h2>Record Name $rn</h2>\n";
58
59my @fields = $rtyp->fields;
60
61#create a Hash to store the table of field information for each GUI type
62%dbdTables = (
63 "GUI_COMMON" => "",
64 "GUI_COMMON" => "",
65 "GUI_ALARMS" => "",
66 "GUI_BITS1" => "",
67 "GUI_BITS2" => "",
68 "GUI_CALC" => "",
69 "GUI_CLOCK" => "",
70 "GUI_COMPRESS" => "",
71 "GUI_CONVERT" => "",
72 "GUI_DISPLAY" => "",
73 "GUI_HIST" => "",
74 "GUI_INPUTS" => "",
75 "GUI_LINKS" => "",
76 "GUI_MBB" => "",
77 "GUI_MOTOR" => "",
78 "GUI_OUTPUT" => "",
79 "GUI_PID" => "",
80 "GUI_PULSE" => "",
81 "GUI_SELECT" => "",
82 "GUI_SEQ1" => "",
83 "GUI_SEQ2" => "",
84 "GUI_SEQ3" => "",
85 "GUI_SUB" => "",
86 "GUI_TIMER" => "",
87 "GUI_WAVE" => "",
88 "GUI_SCAN" => "",
89 "GUI_NONE" => ""
90);
91
92
93#Loop over all of the fields. Build a string that contains the table body
94#for each of the GUI Types based on which fields go with which GUI type.
95foreach $fVal (@fields) {
96 my $pg = $fVal->attribute('promptgroup');
97 while ( ($typ1, $content) = each %dbdTables) {
98 if ( $pg eq $typ1 or ($pg eq "" and $typ1 eq "GUI_NONE")) {
99 buildTableRow($fVal, $dbdTables{$typ1} );
100 }
101 }
102}
103
104#Write out each table
105while ( ($typ2, $content) = each %dbdTables) {
106 printHtmlTable($typ2, $content);
107}
108
109
110#add a field to a table body. The specified field and table body are passed
111#in as parameters
112sub buildTableRow {
113 my ( $fld, $outStr) = @_;
114 $longDesc = "&nbsp;";
115 %htmlCellFmt = (
116 rowStart => "<tr><td rowspan = \"2\">",
117 nextCell => "</td><td>",
118 endRow => "</td></tr>",
119 nextRow => "<tr><td colspan = \"7\" align=left>"
120 );
121 my %cellFmt = %htmlCellFmt;
122 my $rowStart = $cellFmt{rowStart};
123 my $nextCell = $cellFmt{nextCell};
124 my $endRow = $cellFmt{endRow};
125 my $nextRow = $cellFmt{nextRow};
126 $outStr = $outStr . $rowStart;
127 $outStr = $outStr . $fld->name;
128 $outStr = $outStr . $nextCell;
129 $outStr = $outStr . $fld->attribute('prompt');
130 $outStr = $outStr . $nextCell;
131 my $recType = $fld->dbf_type;
132 $typStr = $recType;
133 if ($recType eq "DBF_STRING") {
134 $typStr = $recType . " [" . $fld->attribute('size') . "]";
135 }
136
137 $outStr = $outStr . $typStr;
138 $outStr = $outStr . $nextCell;
139 $outStr = $outStr . design($fld);
140 $outStr = $outStr . $nextCell;
141 my $initial = $fld->attribute('initial');
142 if ( $initial eq '' ) {$initial = "&nbsp;";}
143 $outStr = $outStr . $initial;
144 $outStr = $outStr . $nextCell;
145 $outStr = $outStr . readable($fld);
146 $outStr = $outStr . $nextCell;
147 $outStr = $outStr . writable($fld);
148 $outStr = $outStr . $nextCell;
149 $outStr = $outStr . processPassive($fld);
150 $outStr = $outStr . $endRow;
151 $outStr = $outStr . "\n";
152 $outStr = $outStr . $nextRow;
153 $outStr = $outStr . $longDesc;
154 $outStr = $outStr . $endRow;
155 $outStr = $outStr . "\n";
156 $_[1] = $outStr;
157}
158
159#Check if the prompt group is defined so that this can be used by clients
160sub design {
161 my $fld = $_[0];
162 my $pg = $fld->attribute('promptgroup');
163 if ( $pg eq '' ) {
164 my $result = 'No';
165 }
166 else {
167 my $result = 'Yes';
168 }
169}
170
171#Check if this field is readable by clients
172sub readable {
173 my $fld = $_[0];
174 if ( $fld->attribute('special') eq "SPC_DBADDR") {
175 $return = "Probably";
176 }
177 else{
178 if ( $fld->dbf_type eq "DBF_NOACCESS" ) {
179 $return = "No";
180 }
181 else {
182 $return = "Yes"
183 }
184 }
185}
186
187#Check if this field is writable by clients
188sub writable {
189 my $fld = $_[0];
190 my $spec = $fld->attribute('special');
191 if ( $spec eq "SPC_NOMOD" ) {
192 $return = "No";
193 }
194 else {
195 if ( $spec ne "SPC_DBADDR") {
196 if ( $fld->dbf_type eq "DBF_NOACCESS" ) {
197 $return = "No";
198 }
199 else {
200 $return = "Yes";
201 }
202 }
203 else {
204 $return = "Maybe";
205 }
206 }
207}
208
209
210#Check to see if the field is process passive on caput
211sub processPassive {
212 my $fld = $_[0];
213 $pp = $fld->attribute('pp');
214 if ( $pp eq "YES" or $pp eq "TRUE" ) {
215 $result = "Yes";
216 }
217 elsif ( $PP eq "NO" or $pp eq "FALSE" or $pp eq "" ) {
218 $result = "No";
219 }
220}
221
222#print the start row to define a table
223sub printTableStart {
224 print $out "<table border =\"1\"> \n";
225 print $out "<caption><em>$_[0]</em></caption>";
226 print $out "<th>Field</th>\n";
227 print $out "<th>Summary</th>\n";
228 print $out "<th>Type</th>\n";
229 print $out "<th>DCT</th>\n";
230 print $out "<th>Default</th>\n";
231 print $out "<th>Read</th>\n";
232 print $out "<th>Write</th>\n";
233 print $out "<th>caPut=PP</th></tr>\n";
234
235}
236
237#print the tail end of the table
238sub printTableEnd {
239 print $out "</table>\n";
240}
241
242# Print the table for a GUI type. The name of the GUI type and the Table body
243# for this type are fed in as parameters
244sub printHtmlTable {
245 my ($typ2, $content) = $_;
246 if ( (length $_[1]) gt 0) {
247 printTableStart($_[0]);
248 print $out "$_[1]\n";
249 printTableEnd();
250 }
251
252}
0253
=== added file 'src/tools/dbdToMenuH.pl'
--- src/tools/dbdToMenuH.pl 1970-01-01 00:00:00 +0000
+++ src/tools/dbdToMenuH.pl 2012-04-02 20:38:19 +0000
@@ -0,0 +1,80 @@
1#!/usr/bin/perl
2
3#*************************************************************************
4# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.
6# EPICS BASE is distributed subject to a Software License Agreement found
7# in file LICENSE that is included with this distribution.
8#*************************************************************************
9
10# $Id$
11
12use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";
14
15use EPICS::Getopts;
16use File::Basename;
17use DBD;
18use DBD::Parser;
19use EPICS::macLib;
20use EPICS::Readfile;
21
22my $tool = 'dbdToMenuH.pl';
23
24use vars qw($opt_D @opt_I $opt_o $opt_s);
25getopts('DI@o:') or
26 die "Usage: $tool: [-D] [-I dir] [-o menu.h] menu.dbd [menu.h]\n";
27
28my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
29my $dbd = DBD->new();
30
31my $infile = shift @ARGV;
32$infile =~ m/\.dbd$/ or
33 die "$tool: Input file '$infile' must have '.dbd' extension\n";
34my $inbase = basename($infile);
35
36my $outfile;
37if ($opt_o) {
38 $outfile = $opt_o;
39} elsif (@ARGV) {
40 $outfile = shift @ARGV;
41} else {
42 ($outfile = $infile) =~ s/\.dbd$/.h/;
43 $outfile =~ s/^.*\///;
44}
45my $outbase = basename($outfile);
46
47# Derive a name for the include guard
48my $guard_name = "INC_$outbase";
49$guard_name =~ tr/a-zA-Z0-9_/_/cs;
50$guard_name =~ s/(_[hH])?$/_H/;
51
52&ParseDBD($dbd, &Readfile($infile, 0, \@opt_I));
53
54if ($opt_D) {
55 my %filecount;
56 my @uniqfiles = grep { not $filecount{$_}++ } @inputfiles;
57 print "$outfile: ", join(" \\\n ", @uniqfiles), "\n\n";
58 print map { "$_:\n" } @uniqfiles;
59} else {
60 open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n";
61 print OUTFILE "/* $outbase generated from $inbase */\n\n",
62 "#ifndef $guard_name\n",
63 "#define $guard_name\n\n";
64 my $menus = $dbd->menus;
65 while (my ($name, $menu) = each %{$menus}) {
66 print OUTFILE $menu->toDeclaration;
67 }
68# FIXME: Where to put metadata for widely used menus?
69# In the generated menu.h file is wrong: can't create a list of menu.h files.
70# Can only rely on registerRecordDeviceDriver output, so we must require that
71# all such menus be named "menu...", and any other menus must be defined in
72# the record.dbd file that needs them.
73# print OUTFILE "\n#ifdef GEN_MENU_METADATA\n\n";
74# while (($name, $menu) = each %{$menus}) {
75# print OUTFILE $menu->toDefinition;
76# }
77# print OUTFILE "\n#endif /* GEN_MENU_METADATA */\n";
78 print OUTFILE "\n#endif /* $guard_name */\n";
79 close OUTFILE;
80}
081
=== added file 'src/tools/dbdToRecordtypeH.pl'
--- src/tools/dbdToRecordtypeH.pl 1970-01-01 00:00:00 +0000
+++ src/tools/dbdToRecordtypeH.pl 2012-04-02 20:38:19 +0000
@@ -0,0 +1,231 @@
1#!/usr/bin/perl
2
3#*************************************************************************
4# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
5# National Laboratory.
6# EPICS BASE is distributed subject to a Software License Agreement found
7# in file LICENSE that is included with this distribution.
8#*************************************************************************
9
10# $Id$
11
12use FindBin qw($Bin);
13use lib "$Bin/../../lib/perl";
14
15use EPICS::Getopts;
16use File::Basename;
17use DBD;
18use DBD::Parser;
19use EPICS::macLib;
20use EPICS::Readfile;
21
22my $tool = 'dbdToRecordtypeH.pl';
23
24use vars qw($opt_D @opt_I $opt_o $opt_s);
25getopts('DI@o:s') or
26 die "Usage: $tool [-D] [-I dir] [-o xRecord.h] xRecord.dbd [xRecord.h]\n";
27
28my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32?
29my $dbd = DBD->new();
30
31my $infile = shift @ARGV;
32$infile =~ m/\.dbd$/ or
33 die "$tool: Input file '$infile' must have '.dbd' extension\n";
34my $inbase = basename($infile);
35
36my $outfile;
37if ($opt_o) {
38 $outfile = $opt_o;
39} elsif (@ARGV) {
40 $outfile = shift @ARGV;
41} else {
42 ($outfile = $infile) =~ s/\.dbd$/.h/;
43 $outfile =~ s/^.*\///;
44 $outfile =~ s/dbCommonRecord/dbCommon/;
45}
46my $outbase = basename($outfile);
47
48# Derive a name for the include guard
49my $guard_name = "INC_$outbase";
50$guard_name =~ tr/a-zA-Z0-9_/_/cs;
51$guard_name =~ s/(_[hH])?$/_H/;
52
53&ParseDBD($dbd, &Readfile($infile, 0, \@opt_I));
54
55my $rtypes = $dbd->recordtypes;
56die "$tool: Input file must contain a single recordtype definition.\n"
57 unless (1 == keys %{$rtypes});
58
59if ($opt_D) { # Output dependencies only, to stdout
60 my %filecount;
61 my @uniqfiles = grep { not $filecount{$_}++ } @inputfiles;
62 print "$outfile: ", join(" \\\n ", @uniqfiles), "\n\n";
63 print map { "$_:\n" } @uniqfiles;
64} else {
65 open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n";
66 print OUTFILE "/* $outbase generated from $inbase */\n\n",
67 "#ifndef $guard_name\n",
68 "#define $guard_name\n\n";
69
70 our ($rn, $rtyp) = each %{$rtypes};
71
72 print OUTFILE $rtyp->toCdefs;
73
74 my @menu_fields = grep {
75 $_->dbf_type eq 'DBF_MENU'
76 } $rtyp->fields;
77 my %menu_used;
78 grep {
79 !$menu_used{$_}++
80 } map {
81 $_->attribute('menu')
82 } @menu_fields;
83 our $menus_defined = $dbd->menus;
84 while (my ($name, $menu) = each %{$menus_defined}) {
85 print OUTFILE $menu->toDeclaration;
86 if ($menu_used{$name}) {
87 delete $menu_used{$name}
88 } else {
89 warn "Menu '$name' defined but not used\n";
90 }
91 }
92 our @menus_external = keys %menu_used;
93
94 print OUTFILE $rtyp->toDeclaration;
95
96 unless ($rn eq 'dbCommon') {
97 my $n = 0;
98 print OUTFILE "typedef enum {\n",
99 join(",\n",
100 map { "\t${rn}Record$_ = " . $n++ } $rtyp->field_names),
101 "\n} ${rn}FieldIndex;\n\n";
102 print OUTFILE "#ifdef GEN_SIZE_OFFSET\n\n";
103 if ($opt_s) {
104 &newtables;
105 } else {
106 &oldtables;
107 }
108 print OUTFILE "#endif /* GEN_SIZE_OFFSET */\n";
109 }
110 print OUTFILE "\n",
111 "#endif /* $guard_name */\n";
112 close OUTFILE;
113}
114
115sub oldtables {
116 # Output compatible with R3.14.x
117 print OUTFILE "#ifdef __cplusplus\n" .
118 "extern \"C\" {\n" .
119 "#endif\n" .
120 "#include <epicsExport.h>\n" .
121 "static int ${rn}RecordSizeOffset(dbRecordType *prt)\n" .
122 "{\n" .
123 " ${rn}Record *prec = 0;\n" .
124 join("\n", map {
125 " prt->papFldDes[${rn}Record" . $_->name . "]->size = " .
126 "sizeof(prec->" . $_->C_name . ");"
127 } $rtyp->fields) . "\n" .
128 join("\n", map {
129 " prt->papFldDes[${rn}Record" . $_->name . "]->offset = " .
130 "(char *)&prec->" . $_->C_name . " - (char *)prec;"
131 } $rtyp->fields) . "\n" .
132 " prt->rec_size = sizeof(*prec);\n" .
133 " return 0;\n" .
134 "}\n" .
135 "epicsExportRegistrar(${rn}RecordSizeOffset);\n\n" .
136 "#ifdef __cplusplus\n" .
137 "}\n" .
138 "#endif\n";
139}
140
141sub newtables {
142 # Output for an eventual DBD-less IOC
143 print OUTFILE (map {
144 "extern const dbMenu ${_}MenuMetaData;\n"
145 } @menus_external), "\n";
146 while (my ($name, $menu) = each %{$menus_defined}) {
147 print OUTFILE $menu->toDefinition;
148 }
149 print OUTFILE (map {
150 "static const char ${rn}FieldName$_\[] = \"$_\";\n" }
151 $rtyp->field_names), "\n";
152 my $n = 0;
153 print OUTFILE "static const dbRecordData ${rn}RecordMetaData;\n\n",
154 "static dbFldDes ${rn}FieldMetaData[] = {\n",
155 join(",\n", map {
156 my $fn = $_->name;
157 my $cn = $_->C_name;
158 " { ${rn}FieldName${fn}," .
159 $_->dbf_type . ',"' .
160 $_->attribute('initial') . '",' .
161 ($_->attribute('special') || '0') . ',' .
162 ($_->attribute('pp') || 'FALSE') . ',' .
163 ($_->attribute('interest') || '0') . ',' .
164 ($_->attribute('asl') || 'ASL0') . ',' .
165 $n++ . ",\n\t\&${rn}RecordMetaData," .
166 "GEOMETRY_DATA(${rn}Record,$cn) }";
167 } $rtyp->fields),
168 "\n};\n\n";
169 print OUTFILE "static const ${rn}FieldIndex ${rn}RecordLinkFieldIndices[] = {\n",
170 join(",\n", map {
171 " ${rn}Record" . $_->name;
172 } grep {
173 $_->dbf_type =~ m/^DBF_(IN|OUT|FWD)LINK/;
174 } $rtyp->fields),
175 "\n};\n\n";
176 my @sorted_names = sort $rtyp->field_names;
177 print OUTFILE "static const char * const ${rn}RecordSortedFieldNames[] = {\n",
178 join(",\n", map {
179 " ${rn}FieldName$_"
180 } @sorted_names),
181 "\n};\n\n";
182 print OUTFILE "static const ${rn}FieldIndex ${rn}RecordSortedFieldIndices[] = {\n",
183 join(",\n", map {
184 " ${rn}Record$_"
185 } @sorted_names),
186 "\n};\n\n";
187 print OUTFILE "extern rset ${rn}RSET;\n\n",
188 "static const dbRecordData ${rn}RecordMetaData = {\n",
189 " \"$rn\",\n",
190 " sizeof(${rn}Record),\n",
191 " NELEMENTS(${rn}FieldMetaData),\n",
192 " ${rn}FieldMetaData,\n",
193 " ${rn}RecordVAL,\n",
194 " \&${rn}FieldMetaData[${rn}RecordVAL],\n",
195 " NELEMENTS(${rn}RecordLinkFieldIndices),\n",
196 " ${rn}RecordLinkFieldIndices,\n",
197 " ${rn}RecordSortedFieldNames,\n",
198 " ${rn}RecordSortedFieldIndices,\n",
199 " \&${rn}RSET\n",
200 "};\n\n",
201 "#ifdef __cplusplus\n",
202 "extern \"C\" {\n",
203 "#endif\n\n";
204 print OUTFILE "dbRecordType * epicsShareAPI ${rn}RecordRegistrar(dbBase *pbase, int nDevs)\n",
205 "{\n",
206 " dbRecordType *prt = dbCreateRecordtype(&${rn}RecordMetaData, nDevs);\n";
207 print OUTFILE " ${rn}FieldMetaData[${rn}RecordDTYP].typDat.pdevMenu = \&prt->devMenu;\n";
208 while (my ($name, $menu) = each %{$menus_defined}) {
209 print OUTFILE " dbRegisterMenu(pbase, \&${name}MenuMetaData);\n";
210 }
211 print OUTFILE map {
212 " ${rn}FieldMetaData[${rn}Record" .
213 $_->name .
214 "].typDat.pmenu = \n".
215 " \&" .
216 $_->attribute('menu') .
217 "MenuMetaData;\n";
218 } @menu_fields;
219 print OUTFILE map {
220 " ${rn}FieldMetaData[${rn}Record" .
221 $_->name .
222 "].typDat.base = CT_HEX;\n";
223 } grep {
224 $_->attribute('base') eq 'HEX';
225 } $rtyp->fields;
226 print OUTFILE " dbRegisterRecordtype(pbase, prt);\n";
227 print OUTFILE " return prt;\n}\n\n",
228 "#ifdef __cplusplus\n",
229 "} /* extern \"C\" */\n",
230 "#endif\n\n";
231}
0232
=== added directory 'src/tools/test'
=== added file 'src/tools/test/Breaktable.plt'
--- src/tools/test/Breaktable.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Breaktable.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,22 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 9;
7
8use DBD::Breaktable;
9
10my $bpt = DBD::Breaktable->new('test');
11isa_ok $bpt, 'DBD::Breaktable';
12is $bpt->name, 'test', 'Breakpoint table name';
13is $bpt->points, 0, 'Points == zero';
14$bpt->add_point(0, 0.5);
15is $bpt->points, 1, 'First point added';
16is_deeply $bpt->point(0), [0, 0.5], 'First point correct';
17$bpt->add_point(1, 1.5);
18is $bpt->points, 2, 'Second point added';
19is_deeply $bpt->point(0), [0, 0.5], 'First point still correct';
20is_deeply $bpt->point(1), [1, 1.5], 'Second point correct';
21is_deeply $bpt->point(2), undef, 'Third point undefined';
22
023
=== added file 'src/tools/test/DBD.plt'
--- src/tools/test/DBD.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/DBD.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,60 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 18;
7
8use DBD;
9
10my $dbd = DBD->new;
11isa_ok $dbd, 'DBD';
12
13is keys %{$dbd->breaktables}, 0, 'No breaktables yet';
14my $brk = DBD::Breaktable->new('Brighton');
15$dbd->add($brk);
16my %brks = %{$dbd->breaktables};
17is_deeply \%brks, {Brighton => $brk}, 'Added breaktable';
18
19is keys %{$dbd->drivers}, 0, 'No drivers yet';
20my $drv = DBD::Driver->new('Danforth');
21$dbd->add($drv);
22my %drvs = %{$dbd->drivers};
23is_deeply \%drvs, {Danforth => $drv}, 'Added driver';
24
25is keys %{$dbd->functions}, 0, 'No functions yet';
26my $fnc = DBD::Function->new('Frank');
27$dbd->add($fnc);
28my %fncs = %{$dbd->functions};
29is_deeply \%fncs, {Frank => $fnc}, 'Added function';
30
31is keys %{$dbd->menus}, 0, 'No menus yet';
32my $menu = DBD::Menu->new('Mango');
33$dbd->add($menu);
34my %menus = %{$dbd->menus};
35is_deeply \%menus, {Mango => $menu}, 'Added menu';
36is $dbd->menu('Mango'), $menu, 'Named menu';
37
38is keys %{$dbd->recordtypes}, 0, 'No recordtypes yet';
39my $rtyp = DBD::Recordtype->new('Rita');
40$dbd->add($rtyp);
41my %rtypes = %{$dbd->recordtypes};
42is_deeply \%rtypes, {Rita => $rtyp}, 'Added recordtype';
43is $dbd->recordtype('Rita'), $rtyp, 'Named recordtype';
44
45is keys %{$dbd->registrars}, 0, 'No registrars yet';
46my $reg = DBD::Registrar->new('Reggie');
47$dbd->add($reg);
48my %regs = %{$dbd->registrars};
49is_deeply \%regs, {Reggie => $reg}, 'Added registrar';
50
51is keys %{$dbd->variables}, 0, 'No variables yet';
52my $ivar = DBD::Variable->new('IntVar');
53my $dvar = DBD::Variable->new('DblVar', 'double');
54$dbd->add($ivar);
55my %vars = %{$dbd->variables};
56is_deeply \%vars, {IntVar => $ivar}, 'First variable';
57$dbd->add($dvar);
58%vars = %{$dbd->variables};
59is_deeply \%vars, {IntVar => $ivar, DblVar => $dvar}, 'Second variable';
60
061
=== added file 'src/tools/test/Device.plt'
--- src/tools/test/Device.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Device.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,33 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 16;
7
8use DBD::Device;
9
10my $dev = DBD::Device->new('VME_IO', 'test', '"Device"');
11isa_ok $dev, 'DBD::Device';
12is $dev->name, 'test', 'Device name';
13is $dev->link_type, 'VME_IO', 'Link type';
14is $dev->choice, 'Device', 'Choice string';
15ok $dev->legal_addr('#C0xFEED S123 @xxx'), 'Address legal';
16my %dev_addrs = (
17 CONSTANT => '12345',
18 PV_LINK => 'Any:Record.NAME CPP.MS',
19 VME_IO => '# C1 S2 @Anything',
20 CAMAC_IO => '# B1 C2 N3 A4 F5 @Anything',
21 RF_IO => '# R1 M2 D3 E4',
22 AB_IO => '# L1 A2 C3 S4 @Anything',
23 GPIB_IO => '# L1 A2 @Anything',
24 BITBUS_IO => '# L1 N2 P3 S4 @Anything',
25 BBGPIB_IO => '# L1 B2 G3 @Anything',
26 VXI_IO => '# V1 C2 S3 @Anything',
27 INST_IO => '@Anything'
28);
29while (my ($link, $addr) = each(%dev_addrs)) {
30 $dev->init($link, 'test', '"Device"');
31 ok $dev->legal_addr($addr), "$link address";
32}
33
034
=== added file 'src/tools/test/Driver.plt'
--- src/tools/test/Driver.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Driver.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,13 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 2;
7
8use DBD::Driver;
9
10my $drv = DBD::Driver->new('test');
11isa_ok $drv, 'DBD::Driver';
12is $drv->name, 'test', 'Driver name';
13
014
=== added file 'src/tools/test/Function.plt'
--- src/tools/test/Function.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Function.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,13 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 2;
7
8use DBD::Function;
9
10my $func = DBD::Function->new('test');
11isa_ok $func, 'DBD::Function';
12is $func->name, 'test', 'Function name';
13
014
=== added file 'src/tools/test/Makefile'
--- src/tools/test/Makefile 1970-01-01 00:00:00 +0000
+++ src/tools/test/Makefile 2012-04-02 20:38:19 +0000
@@ -0,0 +1,26 @@
1#*************************************************************************
2# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
3# National Laboratory.
4# EPICS BASE is distributed subject to a Software License Agreement found
5# in the file LICENSE that is included with this distribution.
6#*************************************************************************
7TOP=../../..
8
9include $(TOP)/configure/CONFIG
10
11TESTS += Breaktable
12TESTS += DBD
13TESTS += Device
14TESTS += Driver
15TESTS += Function
16TESTS += macLib
17TESTS += Menu
18TESTS += Recfield
19TESTS += Recordtype
20TESTS += Registrar
21TESTS += Variable
22
23TESTSCRIPTS_HOST += $(TESTS:%=%.t)
24
25include $(TOP)/configure/RULES
26
027
=== added file 'src/tools/test/Menu.plt'
--- src/tools/test/Menu.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Menu.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,32 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 14;
7
8use DBD::Menu;
9
10my $menu = DBD::Menu->new('test');
11isa_ok $menu, 'DBD::Menu';
12is $menu->name, 'test', 'Menu name';
13is $menu->choices, 0, 'Choices == zero';
14$menu->add_choice('ch1', '"Choice 1"');
15is $menu->choices, 1, 'First choice added';
16ok $menu->legal_choice('Choice 1'), 'First choice legal';
17is_deeply $menu->choice(0), ['ch1', 'Choice 1'], 'First choice found';
18$menu->add_choice('ch2', '"Choice 2"');
19is $menu->choices, 2, 'Second choice added';
20ok $menu->legal_choice('Choice 1'), 'First choice still legal';
21is_deeply $menu->choice(0), ['ch1', 'Choice 1'], 'First choice still found';
22ok $menu->legal_choice('Choice 2'), 'Second choice legal';
23is_deeply $menu->choice(1), ['ch2', 'Choice 2'], 'Second choice found';
24ok !$menu->legal_choice('Choice 3'), 'Third choice not legal';
25is_deeply $menu->choice(2), undef, 'Third choice undefined';
26
27like $menu->toDeclaration, qr/ ^
28 \s* typedef \s+ enum \s+ {
29 \s+ ch1 \s+ \/\* [^*]* \*\/,
30 \s+ ch2 \s+ \/\* [^*]* \*\/,
31 \s+ test_NUM_CHOICES ,?
32 \s+ } \s+ test; \s* $ /x, 'C declaration';
033
=== added file 'src/tools/test/Recfield.plt'
--- src/tools/test/Recfield.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Recfield.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,114 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 76;
7
8use DBD::Recfield;
9
10my $fld_string = DBD::Recfield->new('str', 'DBF_STRING');
11isa_ok $fld_string, 'DBD::Recfield';
12isa_ok $fld_string, 'DBD::Recfield::DBF_STRING';
13$fld_string->set_number(0);
14is $fld_string->number, 0, 'Field number';
15$fld_string->add_attribute("size", "41");
16is keys %{$fld_string->attributes}, 1, "Size set";
17ok $fld_string->legal_value("Hello, world!"), 'Legal value';
18ok !$fld_string->legal_value("x"x41), 'Illegal string';
19$fld_string->check_valid;
20like $fld_string->toDeclaration, qr/^\s*char\s+str\[41\];\s*$/, "C declaration";
21
22my $fld_char = DBD::Recfield->new('chr', 'DBF_CHAR');
23isa_ok $fld_char, 'DBD::Recfield';
24isa_ok $fld_char, 'DBD::Recfield::DBF_CHAR';
25is $fld_char->name, 'chr', 'Field name';
26is $fld_char->dbf_type, 'DBF_CHAR', 'Field type';
27ok !$fld_char->legal_value("-129"), 'Illegal - value';
28ok $fld_char->legal_value("-128"), 'Legal - value';
29ok $fld_char->legal_value("127"), 'Legal + value';
30ok !$fld_char->legal_value("0x80"), 'Illegal + hex value';
31$fld_char->check_valid;
32like $fld_char->toDeclaration, qr/^\s*epicsInt8\s+chr;\s*$/, "C declaration";
33
34my $fld_uchar = DBD::Recfield->new('uchr', 'DBF_UCHAR');
35isa_ok $fld_uchar, 'DBD::Recfield';
36isa_ok $fld_uchar, 'DBD::Recfield::DBF_UCHAR';
37is $fld_uchar->name, 'uchr', 'Field name';
38is $fld_uchar->dbf_type, 'DBF_UCHAR', 'Field type';
39ok !$fld_uchar->legal_value("-1"), 'Illegal - value';
40ok $fld_uchar->legal_value("0"), 'Legal 0 value';
41ok $fld_uchar->legal_value("0377"), 'Legal + value';
42ok !$fld_uchar->legal_value("0400"), 'Illegal + octal value';
43$fld_uchar->check_valid;
44like $fld_uchar->toDeclaration, qr/^\s*epicsUInt8\s+uchr;\s*$/, "C declaration";
45
46my $fld_short = DBD::Recfield->new('shrt', 'DBF_SHORT');
47isa_ok $fld_short, 'DBD::Recfield';
48isa_ok $fld_short, 'DBD::Recfield::DBF_SHORT';
49is $fld_short->name, 'shrt', 'Field name';
50is $fld_short->dbf_type, 'DBF_SHORT', 'Field type';
51ok !$fld_short->legal_value("-32769"), 'Illegal - value';
52ok $fld_short->legal_value("-32768"), 'Legal - value';
53ok $fld_short->legal_value("32767"), 'Legal + value';
54ok !$fld_short->legal_value("0x8000"), 'Illegal + hex value';
55$fld_short->check_valid;
56like $fld_short->toDeclaration, qr/^\s*epicsInt16\s+shrt;\s*$/, "C declaration";
57
58my $fld_ushort = DBD::Recfield->new('ushrt', 'DBF_USHORT');
59isa_ok $fld_ushort, 'DBD::Recfield';
60isa_ok $fld_ushort, 'DBD::Recfield::DBF_USHORT';
61is $fld_ushort->name, 'ushrt', 'Field name';
62is $fld_ushort->dbf_type, 'DBF_USHORT', 'Field type';
63ok !$fld_ushort->legal_value("-1"), 'Illegal - value';
64ok $fld_ushort->legal_value("0"), 'Legal 0 value';
65ok $fld_ushort->legal_value("65535"), 'Legal + value';
66ok !$fld_ushort->legal_value("0x10000"), 'Illegal + hex value';
67$fld_ushort->check_valid;
68like $fld_ushort->toDeclaration, qr/^\s*epicsUInt16\s+ushrt;\s*$/, "C declaration";
69
70my $fld_long = DBD::Recfield->new('lng', 'DBF_LONG');
71isa_ok $fld_long, 'DBD::Recfield';
72isa_ok $fld_long, 'DBD::Recfield::DBF_LONG';
73is $fld_long->name, 'lng', 'Field name';
74is $fld_long->dbf_type, 'DBF_LONG', 'Field type';
75ok $fld_long->legal_value("-12345678"), 'Legal - value';
76ok $fld_long->legal_value("0x12345678"), 'Legal + value';
77ok !$fld_long->legal_value("0xfigure"), 'Illegal value';
78$fld_long->check_valid;
79like $fld_long->toDeclaration, qr/^\s*epicsInt32\s+lng;\s*$/, "C declaration";
80
81my $fld_ulong = DBD::Recfield->new('ulng', 'DBF_ULONG');
82isa_ok $fld_ulong, 'DBD::Recfield';
83isa_ok $fld_ulong, 'DBD::Recfield::DBF_ULONG';
84is $fld_ulong->name, 'ulng', 'Field name';
85is $fld_ulong->dbf_type, 'DBF_ULONG', 'Field type';
86ok !$fld_ulong->legal_value("-1"), 'Illegal - value';
87ok $fld_ulong->legal_value("00"), 'Legal 0 value';
88ok $fld_ulong->legal_value("0xffffffff"), 'Legal + value';
89ok !$fld_ulong->legal_value("0xfacepaint"), 'Illegal value';
90$fld_ulong->check_valid;
91like $fld_ulong->toDeclaration, qr/^\s*epicsUInt32\s+ulng;\s*$/, "C declaration";
92
93my $fld_float = DBD::Recfield->new('flt', 'DBF_FLOAT');
94isa_ok $fld_float, 'DBD::Recfield';
95isa_ok $fld_float, 'DBD::Recfield::DBF_FLOAT';
96is $fld_float->name, 'flt', 'Field name';
97is $fld_float->dbf_type, 'DBF_FLOAT', 'Field type';
98ok $fld_float->legal_value("-1.2345678e9"), 'Legal - value';
99ok $fld_float->legal_value("0.12345678e9"), 'Legal + value';
100ok !$fld_float->legal_value("0x1.5"), 'Illegal value';
101$fld_float->check_valid;
102like $fld_float->toDeclaration, qr/^\s*epicsFloat32\s+flt;\s*$/, "C declaration";
103
104my $fld_double = DBD::Recfield->new('dbl', 'DBF_DOUBLE');
105isa_ok $fld_double, 'DBD::Recfield';
106isa_ok $fld_double, 'DBD::Recfield::DBF_DOUBLE';
107is $fld_double->name, 'dbl', 'Field name';
108is $fld_double->dbf_type, 'DBF_DOUBLE', 'Field type';
109ok $fld_double->legal_value("-12345e-67"), 'Legal - value';
110ok $fld_double->legal_value("12345678e+9"), 'Legal + value';
111ok !$fld_double->legal_value("e5"), 'Illegal value';
112$fld_double->check_valid;
113like $fld_double->toDeclaration, qr/^\s*epicsFloat64\s+dbl;\s*$/, "C declaration";
114
0115
=== added file 'src/tools/test/Recordtype.plt'
--- src/tools/test/Recordtype.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Recordtype.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,57 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 17;
7
8use DBD::Recordtype;
9use DBD::Recfield;
10use DBD::Device;
11
12my $rtyp = DBD::Recordtype->new('test');
13isa_ok $rtyp, 'DBD::Recordtype';
14is $rtyp->name, 'test', 'Record name';
15is $rtyp->fields, 0, 'No fields yet';
16
17my $fld1 = DBD::Recfield->new('NAME', 'DBF_STRING');
18$fld1->add_attribute("size", "41");
19$fld1->check_valid;
20
21my $fld2 = DBD::Recfield->new('DTYP', 'DBF_DEVICE');
22$fld2->check_valid;
23
24$rtyp->add_field($fld1);
25is $rtyp->fields, 1, 'First field added';
26
27$rtyp->add_field($fld2);
28is $rtyp->fields, 2, 'Second field added';
29
30my @fields = $rtyp->fields;
31is_deeply \@fields, [$fld1, $fld2], 'Field list';
32
33my @names = $rtyp->field_names;
34is_deeply \@names, ['NAME', 'DTYP'], 'Field name list';
35
36is $rtyp->field('NAME'), $fld1, 'Field name lookup';
37
38is $fld1->number, 0, 'Field number 0';
39is $fld2->number, 1, 'Field number 1';
40
41is $rtyp->devices, 0, 'No devices yet';
42
43my $dev1 = DBD::Device->new('INST_IO', 'testDset', 'test device');
44$rtyp->add_device($dev1);
45is $rtyp->devices, 1, 'First device added';
46
47my @devices = $rtyp->devices;
48is_deeply \@devices, [$dev1], 'Device list';
49
50is $rtyp->device('test device'), $dev1, 'Device name lookup';
51
52is $rtyp->cdefs, 0, 'No cdefs yet';
53$rtyp->add_cdef("cdef");
54is $rtyp->cdefs, 1, 'First cdef added';
55
56my @cdefs = $rtyp->cdefs;
57is_deeply \@cdefs, ["cdef"], 'cdef list';
058
=== added file 'src/tools/test/Registrar.plt'
--- src/tools/test/Registrar.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Registrar.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,13 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 2;
7
8use DBD::Registrar;
9
10my $reg = DBD::Registrar->new('test');
11isa_ok $reg, 'DBD::Registrar';
12is $reg->name, 'test', 'Registrar name';
13
014
=== added file 'src/tools/test/Variable.plt'
--- src/tools/test/Variable.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/Variable.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,15 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 4;
7
8use DBD::Variable;
9
10my $ivar = DBD::Variable->new('test');
11isa_ok $ivar, 'DBD::Variable';
12is $ivar->name, 'test', 'Variable name';
13is $ivar->var_type, 'int', 'variable defaults to int';
14my $dvar = DBD::Variable->new('test', 'double');
15is $dvar->var_type, 'double', 'double variable';
016
=== added file 'src/tools/test/macLib.plt'
--- src/tools/test/macLib.plt 1970-01-01 00:00:00 +0000
+++ src/tools/test/macLib.plt 2012-04-02 20:38:19 +0000
@@ -0,0 +1,72 @@
1#!/usr/bin/perl
2
3use FindBin qw($Bin);
4use lib "$Bin/../../../../lib/perl";
5
6use Test::More tests => 34;
7
8use EPICS::macLib;
9
10use Data::Dumper;
11
12my $m = EPICS::macLib->new;
13isa_ok $m, 'EPICS::macLib';
14is $m->expandString(''), '', 'Empty string';
15is $m->expandString('$(undef)'), undef, 'Warning $(undef)';
16
17$m->suppressWarning(1);
18is $m->expandString('$(undef)'), '$(undef)', 'Suppressed $(undef)';
19
20$m->putValue('a', 'foo');
21is $m->expandString('$(a)'), 'foo', '$(a)';
22is $m->expandString('${a}'), 'foo', '${a}';
23is $m->expandString('$(a=bar)'), 'foo', '$(a=bar)';
24is $m->expandString('${a=bar}'), 'foo', '${a=bar}';
25is $m->expandString('$(undef)'), '$(undef)', '$(undef) again';
26is $m->expandString('${undef}'), '$(undef)', '${undef} again';
27
28$m->suppressWarning(0);
29is $m->expandString('$(undef=$(a))'), 'foo', '$(undef=$(a))';
30is $m->expandString('${undef=${a}}'), 'foo', '${undef=${a}}';
31is $m->expandString('${undef=$(a)}'), 'foo', '${undef=$(a)}';
32is $m->expandString('$(undef=${a})'), 'foo', '$(undef=${a})';
33is $m->expandString('$(a=$(undef))'), 'foo', '$(a=$(undef))';
34
35$m->putValue('b', 'baz');
36is $m->expandString('$(b)'), 'baz', '$(b)';
37is $m->expandString('$(a)'), 'foo', '$(a)';
38is $m->expandString('$(a)$(b)'), 'foobaz', '$(a)$(b)';
39is $m->expandString('$(a)/$(b)'), 'foo/baz', '$(a)/$(b)';
40is $m->expandString('$(a)\$(b)'), 'foo\$(b)', '$(a)\$(b)';
41is $m->expandString('$(a)$$(b)'), 'foo$baz', '$(a)$$(b)';
42
43$m->putValue('c', '$(a)');
44is $m->expandString('$(c)'), 'foo', '$(c)';
45is $m->expandString('$(undef=$(c))'), 'foo', '$(undef=$(c))';
46
47$m->putValue('d', 'c');
48is $m->expandString('$(d)'), 'c', '$(d)';
49is $m->expandString('$($(d))'), 'foo', '$($(d))';
50is $m->expandString('$($(b)=$(a))'), 'foo', '$($(b)=$(a))';
51
52$m->suppressWarning(1);
53$m->putValue('c', undef);
54is $m->expandString('$(c)'), '$(c)', '$(c) deleted';
55
56$m->installMacros('c=fum,d');
57is $m->expandString('$(c)'), 'fum', 'installMacros, $(c)';
58
59is $m->expandString('$(d)'), '$(d)', 'installMacros deletion';
60
61$m->pushScope;
62is $m->expandString('$(a)'), 'foo', 'pushScope, $(a)';
63$m->putValue('a', 'grinch');
64is $m->expandString('$(a)'), 'grinch', 'new $(a) in child';
65
66$m->putValue('b', undef);
67is $m->expandString('$(b)'), '$(b)', '$(b) deleted in child';
68
69$m->popScope;
70is $m->expandString('$(a)'), 'foo', 'popScope, $(a) restored';
71is $m->expandString('$(b)'), 'baz', '$(b) restored';
72

Subscribers

People subscribed via source and target branches