Compare commits

...

81 Commits

Author SHA1 Message Date
1e64b08c32 bump rpm version
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 1s
Base / Cross linux-aarch64 (push) Failing after 2s
Base / Cross linux-arm gnueabi (push) Failing after 1s
Base / Cross linux-arm gnueabihf (push) Failing after 2s
Base / Fedora-33 (push) Failing after 1s
Base / Fedora-latest (push) Failing after 2s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2024-08-27 13:08:38 +02:00
d67036fcc0 Merge branch 'aliases' into PSI-7.0 2024-08-26 16:37:57 +02:00
d494d91ba2 allow to load the same alias multiple times (unless dbRecordsOnceOnly is set) 2024-08-26 16:30:20 +02:00
Michael Davidsaver
052a0c7e19 test get_enum_strs() 2024-08-21 10:01:26 -05:00
Michael Davidsaver
979dde8376 redo get_enum_strs() to pacify _FORTIFY_SOURCES=3 2024-08-21 10:01:26 -05:00
Michael Davidsaver
9a0113f834 GHA: add gcc with -D_FORTIFY_SOURCE=3 2024-08-21 10:01:26 -05:00
Michael Davidsaver
3d70e70640 Add dbPvt2Rec() cast
Reverse of dbRec2Pvt()

pacify -D_FORTIFY_SOURCE=3 and __builtin_object_size() as
"&precord->common" does not know than common as actually
the prefix of a variable sized struct.
2024-08-21 10:01:26 -05:00
Michael Davidsaver
f9e53dded6 show buffered line along with DB parse error 2024-08-21 09:53:38 -05:00
403ebab858 use more standard permissions for bins and libs 2024-08-21 09:50:26 -05:00
Hinko Kocevar
8e62ea4965 handle deletion of the non-existant record with field 2024-08-21 09:48:23 -05:00
Hinko Kocevar
f00de26be1 directory path name is free'd before it is used in testAbort() 2024-08-21 09:48:23 -05:00
Hinko Kocevar
50b6a3801a check if precordType is null in dbGetRecordTypeName() 2024-08-21 09:48:23 -05:00
Michael Davidsaver
2a5def7fc6 test removal of non-existant record 2024-08-21 09:48:23 -05:00
Michael Davidsaver
fd072e4429 add more information to record(# warning 2024-08-21 09:48:23 -05:00
Hinko Kocevar
3a5c9ab0cd add a warning if deleting a non-existent record 2024-08-21 09:48:23 -05:00
Hinko Kocevar
c735de4ff8 fix number of tests to execute 2024-08-21 09:48:23 -05:00
Hinko Kocevar
bb5423171d remove warning and error messages, fix duplicate flag setting 2024-08-21 09:48:23 -05:00
Hinko Kocevar
4e4e55ca89 invoke dbFreeLinkContents() to clean up link related allocations 2024-08-21 09:48:23 -05:00
Hinko Kocevar
e9748881cd make codacy happy 2024-08-21 09:48:23 -05:00
Hinko Kocevar
39b0301062 plug memory leak resulting from record deletion 2024-08-21 09:48:23 -05:00
Hinko Kocevar
2f98251c9f add unit tests for record deletion 2024-08-21 09:48:23 -05:00
Hinko Kocevar
535c9c2a06 Allow deleting a record at database creation.
Using a magical record type "#" will allow the user to
delete previously created record  from the database.
2024-08-21 09:48:23 -05:00
Michael Davidsaver
057eb87101 readline: only keep history for interactive session 2024-08-21 09:36:39 -05:00
457387ed38 fix warning when dbf_type_to_text is called with an unsigned type argument 2024-08-21 09:35:53 -05:00
b6fffc2225 fix string to epicsUInt32 conversion via double 2024-08-21 09:28:45 -05:00
86cdfc596f fix wrong (unsigned) comparison 2024-08-12 10:29:08 -04:00
Andrew Johnson
3dae29b7e8 Oops, needed stdint.h 2024-08-10 14:45:28 -05:00
Andrew Johnson
9d393c4437 Cast sizeOffset to uintptr_t for ordered comparison
Issue report & fix by Dirk Zimoch.
2024-08-10 13:21:30 -05:00
97ffcb725c fix compile error with gcc 3.4.3 2024-08-09 11:45:20 +02:00
5930e8e2e4 time_t has 64 bit o 64 bit architectures 2024-08-09 11:44:26 +02:00
212f387d1b keep INSTALL_PERMISSIONS non-writable 2024-08-07 17:42:40 +02:00
1ae21cdde4 improve error message more 2024-08-07 17:41:47 +02:00
03f17a08c3 Merge branch '7.0' into PSI-7.0 2024-08-07 17:30:04 +02:00
Andrew Johnson
a5c3330c8e Update .ci module, disable CentOS-7 build 2024-08-07 09:54:16 -05:00
Andrew Johnson
856f345d2c Fix Codacy complaint about C-style casts 2024-08-07 09:54:16 -05:00
Andrew Johnson
3f4d080260 Make dbFastGet/PutConvertRoutine arrays const
Also added Doxygen annotations for them.
2024-08-07 09:54:16 -05:00
Andrew Johnson
1e8d49f2a6 Drop debugging diagnostics 2024-08-07 09:54:16 -05:00
Andrew Johnson
31b22fd253 Add test of jlinkz::putValue() to dbPutLinkTest
Add OUTP link field to xRecord
xRecord::process() puts VAL to the OUTP link
jlinkz writes the output value to the record's own PHAS field
Correct the dbFastPutConvertRoutine lookup
Test sets OUTP link, processes record and confirms that PHAS was set
2024-08-07 09:54:16 -05:00
Andrew Johnson
916b17ef3f Fix review comment 2024-08-07 09:54:16 -05:00
Andrew Johnson
437320926b Move declaration back 2024-08-07 09:54:16 -05:00
Andrew Johnson
7890e67d37 Various misc warnings 2024-08-07 09:54:16 -05:00
Andrew Johnson
918a188285 Define USE_TYPED_DRVET, use drvet * instead of struct drvet * 2024-08-07 09:54:16 -05:00
Andrew Johnson
2f730b8e9f Add arg's to function pointer typedefs and prototypes 2024-08-07 09:54:16 -05:00
Andrew Johnson
1835187a86 Change fast convert routines to match prototype
Most of these edits were make using regexes in find/replace.
2024-08-07 09:54:16 -05:00
Andrew Johnson
f287cfa2ac Introduce & use FASTCONVERTFUNC with full prototype 2024-08-07 09:54:16 -05:00
Andrew Johnson
785237e41a Remove duplicate link libraries 2024-08-07 09:54:16 -05:00
23999a106b use -nologo with rc like with many other MSVC commands 2024-08-07 09:40:29 -05:00
Andrew Johnson
91e1d0ab80 Update release process files 2024-06-27 22:20:19 -05:00
Andrew Johnson
172bfce1f3 Merge 'Release 7.0.8.1' branch into 7.0 2024-06-27 21:07:50 -05:00
Andrew Johnson
615e7e99ce Update version numbers and submodules after release 2024-06-27 20:56:47 -05:00
Andrew Johnson
57c930fbee Release R7.0.8.1
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 1s
Base / Cross linux-aarch64 (push) Failing after 2s
Base / Cross linux-arm gnueabi (push) Failing after 1s
Base / Cross linux-arm gnueabihf (push) Failing after 2s
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Ub-22 gcc-12 c++20 Werror (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
2024-06-27 20:55:03 -05:00
Andrew Johnson
785b777baf Update Release Notes, set version numbers 2024-06-26 14:59:18 -05:00
Andrew Johnson
d0d15ee911 Replace UNRELEASED with 7.0.8.1 2024-06-26 14:59:18 -05:00
Andrew Johnson
5af9c7e50d Revert submodules to versions at R7.0.8 2024-06-26 14:59:18 -05:00
Andrew Johnson
5fe563bed8 Limit _FORTIFY_SOURCE <= 2 2024-06-26 14:58:53 -05:00
Tynan Ford
772c10d904 Fix issue with RSRV_SERVER_PORT above 9999
don't worry about null termination on epicsSnprintf call
2024-06-19 09:38:23 -07:00
Michael Davidsaver
72d50ce274 fix dblsr()
clearly doesn't get called very often...
2024-06-14 16:45:07 -07:00
Michael Davidsaver
0a6b9e4511 dbScan: handle scanStop() before start 2024-06-14 16:45:07 -07:00
be8f8b41ff centralize -g flag for gnu targets 2024-06-13 14:35:43 -07:00
Simon Rose
1b46077096 Fix off by one error in constant link fetch
For long string buffers, we currently write a null terminator one byte
past the end of the buffer. This can be seen with a record of the type

```
record(aai, foo) {
  field(NELM, 1)
  field(FTVL, CHAR)
  field(INP, {const: "foo"})
}
```
where the buffer is only of size 1, but then we write at index 1 (aka
past the end of the buffer).

Co-authored-by: Lucas A. M. Magalhães <lucmaga@gmail.com>
2024-06-12 16:19:36 -07:00
Chris Guerrero
ede745cc34 Update aSubRecord.dbd.pod 2024-06-12 09:14:30 -07:00
Michael Davidsaver
a864f16318 dbCa test sync. improvements 2024-06-11 19:37:23 -07:00
seifalrahman
4c20518864 modifying the condition from (status!=0) to (status>0) to skip the block in case the status variable ==-1 2024-06-11 18:45:33 -07:00
Michael Davidsaver
6ca716a77f iocsh: add more iocshSetError() 2024-06-11 13:52:03 -07:00
Michael Davidsaver
aa77b1c04a iocInit errors say ERROR 2024-06-11 11:14:07 -07:00
Michael Davidsaver
fe4247d57d Send .db parser errors to stderr 2024-06-11 11:14:07 -07:00
Michael Davidsaver
77490d4939 space in errPrintf() output 2024-06-11 11:14:07 -07:00
Michael Davidsaver
0495ac3bc5 WARN for FLNK uses CA without PROC 2024-06-11 11:14:07 -07:00
Michael Davidsaver
4a305a42a7 softMain log iocInit() failure. 2024-06-11 11:14:07 -07:00
DW
11fba63d18 Fix histogram doc 2024-05-29 09:17:03 -05:00
Simon Rose
1db37bcd91 Update release notes 2024-05-29 09:15:35 -05:00
Simon Rose
beec00b403 Fix issue with compress record
The handling of N-to-M array compression was broken with the addition
of the partial buffer option, which broke the bounds check that was
being used.

Note that this also makes the partial buffer option more consistent;
if, for example, you have
```
record(compress, foo) {
  field(ALG, "N to 1 Average")
  field(INP, "bar NPP")
  field(NSAM, 2)
  field(N, 2)
  field(PBUF, YES)
}
```
(with `bar` having, e.g. length 3), then this will now behave as
expected on both of the samples.
2024-05-29 09:15:35 -05:00
DW
4966baf423 fix sizv for printf & fix doc 2024-05-20 09:18:26 -04:00
Michael Davidsaver
e5b4829074 bound lso/lsi to limit of dbAddr::field_size 2024-05-19 11:57:19 -04:00
Ralph Lange
d8b5616772 ci: bump checkout to v4 in check-editorconfig.yml
- fix node16.js usage warning
2024-05-16 10:07:12 +02:00
Ralph Lange
92615a77fe ci: fix last commit (GHA workaround) 2024-05-15 18:04:58 +02:00
Ralph Lange
b3f92d81db ci: add workaround for GHA node20@centos7 failures 2024-05-15 16:57:34 +02:00
Simon Rose
839f764bcb Clean up some potential memory leaks
The watchdog tasks are allocated, but not consistently removed. In
general this doesn't matter: they run in threads that will only
end when the process actually quits. For consistency and for the
purpose of future-proofing, I think there is value in having the
cleanup added in each case.
2024-05-15 09:26:09 -05:00
Simon Rose
4bb50fe664 Memory leak in caservertask.c 2024-05-15 09:26:09 -05:00
Ralph Lange
c77f32b19c Merge pull request #482 from ericonr/calcout-docs
Fix calcout doc typo.
2024-05-03 04:04:41 +09:00
Érico Nogueira
66ce1c2076 Fix calcout doc typo. 2024-05-02 15:29:22 -03:00
92 changed files with 1871 additions and 1127 deletions

2
.ci

Submodule .ci updated: 130e88b709...0e93b70855

14
.gitattributes vendored
View File

@@ -1,9 +1,11 @@
.ci/ export-ignore
.tools/ export-ignore
.github/ export-ignore
.appveyor/ export-ignore
.appveyor.yml export-ignore
README export-subst
.appveyor.yml export-ignore
.appveyor/ export-ignore
.ci/ export-ignore
.github/ export-ignore
.gitmodules export-ignore
.readthedocs.yml export-ignore
.tools/ export-ignore
README export-subst
#Which files need CRLF handling
# default to automatic

View File

@@ -8,6 +8,6 @@ jobs:
editorconfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: EditorConfig-Action
uses: greut/eclint-action@v0

View File

@@ -60,7 +60,10 @@ jobs:
# Remove respective -Wno-error=... flag once it is fixed.
extra: "CMD_CXXFLAGS=-std=c++20
CMD_CPPFLAGS='-fdiagnostics-color
-fstack-protector-strong
-Wformat
-Werror
-Werror=format-security
-Wno-error=deprecated-declarations
-Wno-error=stringop-truncation
-Wno-error=restrict
@@ -68,8 +71,9 @@ jobs:
-Wno-error=nonnull
-Wno-error=dangling-pointer
-Wno-error=format-overflow
-Wno-error=format-security
-Wno-error=stringop-overread'"
-Wno-error=stringop-overread
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3'
CMD_LDFLAGS=-Wl,-z,relro"
- os: ubuntu-20.04
cmp: gcc
@@ -237,10 +241,10 @@ jobs:
matrix:
# Job names also name artifacts, character limitations apply
include:
- name: "CentOS-7"
image: centos:7
cmp: gcc
configuration: default
#- name: "CentOS-7"
# image: centos:7
# cmp: gcc
# configuration: default
- name: "Fedora-33"
image: fedora:33
@@ -284,6 +288,10 @@ jobs:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
if: matrix.image!='centos:7'
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@node16
if: matrix.image=='centos:7'
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: Build main module

View File

@@ -136,19 +136,20 @@ sed -i -e 's|^\./||' "$TDIR"/list.1
# Exclude files
sed \
-e '/\/\.ci\//d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.appveyor\//d' \
-e '/\/\.ci-local\//d' \
-e '/\/\.tools\//d' \
-e '/\/jenkins\//d' \
-e '/\/\.ci\//d' \
-e '/\/\.cproject$/d' \
-e '/\/\.github\//d' \
-e '/\/\.gitmodules$/d' \
-e '/\/\.hgtags$/d' \
-e '/\/\.cproject$/d' \
-e '/\/\.project$/d' \
-e '/\/\.lgtm\.yml$/d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.project$/d' \
-e '/\/\.readthedocs\.yml$/d' \
-e '/\/\.tools\//d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/jenkins\//d' \
"$TDIR"/list.1 > "$TDIR"/list.2
if ! diff -U 0 "$TDIR"/list.1 "$TDIR"/list.2

View File

@@ -27,16 +27,16 @@ RANLIB = $(GNU_BIN)/$(CMPLR_PREFIX)ranlib$(CMPLR_SUFFIX)
ASAN_FLAGS_YES = -fsanitize=address
ASAN_LDFLAGS_YES = $(ASAN_FLAGS_YES)
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
PROF_CFLAGS_YES = -p
GPROF_CFLAGS_YES = -pg
CODE_CFLAGS = $(PROF_CFLAGS_$(PROFILE)) $(GPROF_CFLAGS_$(GPROF))
CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
WARN_CFLAGS_YES = -Wall -Werror-implicit-function-declaration
WARN_CFLAGS_NO = -w
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES = -O3 -g
OPT_CFLAGS_NO = -g

View File

@@ -52,7 +52,7 @@ EPICS_MODIFICATION = 8
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included in the official EPICS version number if zero
EPICS_PATCH_LEVEL = 1
EPICS_PATCH_LEVEL = 2
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)

View File

@@ -2,7 +2,7 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 14
EPICS_CA_MAINTENANCE_VERSION = 4
EPICS_CA_MAINTENANCE_VERSION = 5
# Development flag, set to zero for release versions

View File

@@ -425,7 +425,7 @@ INSTALL_LIB_INSTALLS = $(addprefix $(INSTALL_LIB)/,$(notdir $(LIB_INSTALLS)))
BIN_PERMISSIONS = 755
LIB_PERMISSIONS = 644
SHRLIB_PERMISSIONS = 755
INSTALL_PERMISSIONS = 644
INSTALL_PERMISSIONS = 444
#---------------------------------------------------------------
#

View File

@@ -2,7 +2,7 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 23
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions

View File

@@ -2,7 +2,7 @@
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 23
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
EPICS_LIBCOM_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions

View File

@@ -34,5 +34,9 @@ CFG += TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A)
include $(TOP)/configure/RULES
ifeq ($(GNU),YES)
# Pass compiler flags to preprocessor to enable _FORTIFY_SOURCE
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): CPPFLAGS += $(CFLAGS)
endif
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): toolchain.c
$(PREPROCESS.cpp)

View File

@@ -42,12 +42,6 @@ ARCH_DEP_LDFLAGS += $(ARCH_DEP_FLAGS)
OP_SYS_CFLAGS += -isysroot $(SDK_DIR)
OP_SYS_LDFLAGS += -isysroot $(SDK_DIR)
#--------------------------------------------------
# Always compile in debugging symbol table information
#
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
#-------------------------------------------------------
# Compiler definitions:

View File

@@ -39,12 +39,6 @@ OP_SYS_CFLAGS += -fno-common
#
OP_SYS_CPPFLAGS += -Ddarwin
#
# Always compile in debugging symbol table information
#
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
#
# Libraries for command-line editing.
#

View File

@@ -6,11 +6,3 @@
# GNU_DIR used when COMMANDLINE_LIBRARY is READLINE
#GNU_DIR=C:/cygwin
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -3,10 +3,3 @@
# Site specific definitions for native linux-aarch64 builds
#-------------------------------------------------------
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -47,3 +47,8 @@ COMMANDLINE_LIBRARY ?= EPICS
#else
COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS))
#endif
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2
OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
#endif

View File

@@ -20,8 +20,80 @@ should also be read to understand what has changed since earlier releases:
**This version of EPICS has not been released yet.**
## Changes made on the 7.0 branch since 7.0.8
## Changes made on the 7.0 branch since 7.0.8.1
### Allow to load the same alias multiple times
Aliases can now be defined multiple times as long as they still refer to the
same record, unless the shell variable dbRecordsOnceOnly is set.
This allows to load database files multiple times, even if they contain
alias definitions.
### Allow users to delete previously created records from the database
From this release, record instances and aliases that have already been loaded
by an IOC can be removed from the database again before the call to iocInit
by loading a second instance of the named records but using `"#"` in place of
the record type. Values for the fields are not required or advised, just use
an empty record body { }. This is useful when a template defines records that
are not wanted in some IOCs, without having to split or duplicate the original
template.
For example this will remove the record named "unwanted":
```
record("#", "unwanted") { }
```
-----
## EPICS Release 7.0.8.1
### Limit to `_FORTIFY_SOURCE=2`
GCC versions 12 and beyond and glibc have added some aggressive runtime
checks for buffer overflows in libc functions at runtime, and the
[Ubuntu 2024.04](https://wiki.ubuntu.com/ToolChain/CompilerFlags) release
increased their default gcc fortification level from 2 to 3.
This has started causing EPICS Base builds to fail on that version, and
other OS releases may make that configuration change with similar results.
This release detects a compiler configured with `_FORTIFY_SOURCE=3` and
overrides it to 2.
Later releases of Base will adjust the code, providing information to the
compiler to avoid triggering these incorrect protections.
### Fix issue with compress record
In Base 7.0.8, an update to the compress record was added to allow for certain
algorithms to use partially filled buffers in their computations. Unfortunately,
this broke the behaviour of the records in certain cases. This has been fixed.
### Various minor changes
These included fixing minor memory leaks and documentation corrections. The
`SIZV` field of lsi, lso and printf record VAL fields now can't exceed 32767
characters, to match an internal limit.
### `epicsSocketAccept()` now returns `SOCKET`, not `int`
This might have some effect on downstream modules still using `int`, but the
OS-specific osdSock.h headers which osiSock.h includes have all declared
`SOCKET` (in most casese as a typedef for `int`) for many releases.
This change removes a compiler warning on WIN32.
Further details and the discussion about this change can be found
[here](https://github.com/epics-base/epics-base/pull/458).
### `dbLoadRecords` allows macros with default values
Previously the parser assumed that files containing macro substitutions were
bad if no macro definitions were provided; that assumption was made incorrect
once macro substitutions were allowed to provide a default value.
### Hostname length limit in CA removed
Before this release, the CA client library only handled hostnames in address
list environment variables up to 255 characters long.
This limit has been removed.
-----

View File

@@ -179,14 +179,10 @@ everything that has to be done since it's so easy to miss steps.</p>
<li><tt>git grep UNRELEASED</tt> and insert the module version to any
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
Commit (don't push yet).</li>
<li>Check that the module's Release Notes have been updated to cover
all changes; add items as necessary, and set the module version
number and release date if appropriate. Convert to HTML and view in
a browser to check the formatting:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
number and release date if appropriate.
Commit these changes (don't push).</li>
<li>Edit the module's release version file
@@ -194,14 +190,37 @@ everything that has to be done since it's so easy to miss steps.</p>
<tt>Doxyfile</tt>s in the top-level and/or documentation
directories. In these, set <tt>DEVELOPMENT_FLAG</tt> to 0 and remove
<tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string. Commit these
changes (don't push).</li>
changes (don't push):
<blockquote><tt>
git ci -m 'Final commit for &lt;module-version&gt;'
</tt></blockquote>
</li>
<li>Tag the module:
<blockquote><tt>
git tag -m 'ANJ: Tag for EPICS 7.0.8' &lt;module-version&gt;
git tag -m 'ANJ: Tag for EPICS 7.0.8.2' &lt;module-version&gt;
</tt></blockquote>
</li>
<li>Generate documentation or Release Notes using one of these:
<ul>
<li>For older modules with a RELEASE_NOTES.md file convert it to
HTML and view in a browser to check the formatting as follows:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
<li>For newer modules with release_notes.dox file, generate the
new github-pages website as follows:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
make commit
git push --force upstream gh-pages
</tt></blockquote>
<i>Q: Delay this <tt>git push</tt> until later?</i></li>
</ul></li>
<li>Update the git submodule on the Base-7.0 branch to the
newly-tagged version, check the module's status matches the tag:
<blockquote><tt>
@@ -269,7 +288,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for release' R7.0.8
git tag -m 'ANJ: Tagged for release' R7.0.8.2
</tt></blockquote>
<p>Don't push to GitHub yet.</p>
</td>
@@ -303,12 +322,12 @@ everything that has to be done since it's so easy to miss steps.</p>
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.0<br />
./.tools/make-tar.sh R7.0.8 ../base-7.0.8.tar.gz base-7.0.8/
./.tools/make-tar.sh R7.0.8.2 ../base-7.0.8.2.tar.gz base-7.0.8.2/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
cd ..<br />
gpg --armor --sign --detach-sig base-7.0.8.tar.gz
gpg --armor --sign --detach-sig base-7.0.8.2.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -374,7 +393,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
epics-controls web-server.
<blockquote><tt>
scp base-7.0.8.tar.gz base-7.0.8.tar.gz.asc epics-controls:download/base<br />
scp base-7.0.8.2.tar.gz base-7.0.8.2.tar.gz.asc epics-controls:download/base<br />
</tt></blockquote>
</td>
</tr>
@@ -397,8 +416,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Go to the GitHub
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8">
Create release from tag R7.0.8</a> page.
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8.2">
Create release from tag R7.0.8.2</a> page.
Upload the tar file and its <tt>.asc</tt> signature file to the new
GitHub release page.</td>
</tr>

View File

@@ -4,7 +4,7 @@
Name: epics-base-%{EpicsVersion}
Summary: EPICS Base %{EpicsVersion}
Version: 1
Version: 2
Release: 0%{?dist}
License: EPICS Open License
Group: Development/Languages

View File

@@ -118,7 +118,6 @@ EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)
SRC_DIRS += $(CURDIR)/test
PROD_HOST += ca_test
ca_test_SRCS = ca_test_main.c ca_test.c
ca_test_LIBS = ca Com
ca_test_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
OBJS_vxWorks += ca_test

View File

@@ -676,7 +676,7 @@ union db_access_val{
(type)%(LAST_TYPE+1) == DBR_DOUBLE)
#define dbf_type_to_text(type) \
( ((type) >= -1 && (type) < dbf_text_dim-2) ? \
( ((type+1) >= 0 && (type) < dbf_text_dim-2) ? \
dbf_text[type+1] : dbf_text_invalid )
#define dbf_text_to_type(text, type) \

View File

@@ -23,4 +23,4 @@ dbCore_SRCS += asIocRegister.c
PROD_HOST += ascheck
ascheck_SRCS = ascheck.c
ascheck_LIBS = dbCore ca Com
ascheck_LIBS = dbCore ca

View File

@@ -225,6 +225,11 @@ static void asCaTask(void)
if(asCaDebug) printf("asCaTask has cleared all channels\n");
epicsEventSignal(asCaTaskWait);
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
taskwdRemove(0);
}
void asCaStart(void)

View File

@@ -112,7 +112,7 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
long dbPutSpecial(DBADDR *paddr,int pass)
{
long int (*pspecial)()=NULL;
long int (*pspecial)(struct dbAddr *, int)=NULL;
rset *prset;
dbCommon *precord = paddr->precord;
long status=0;
@@ -145,63 +145,66 @@ long dbPutSpecial(DBADDR *paddr,int pass)
}
static void get_enum_strs(DBADDR *paddr, char **ppbuffer,
rset *prset,long *options)
rset *prset, long *options)
{
short field_type=paddr->field_type;
dbFldDes *pdbFldDes = paddr->pfldDes;
dbMenu *pdbMenu;
dbDeviceMenu *pdbDeviceMenu;
char **papChoice;
unsigned long no_str;
char *ptemp;
struct dbr_enumStrs *pdbr_enumStrs=(struct dbr_enumStrs*)(*ppbuffer);
unsigned int i;
struct dbr_enumStrs *penum=(struct dbr_enumStrs*)(*ppbuffer);
/* advance output buffer on success or failure for next option */
*ppbuffer = dbr_enumStrs_size + (char*)penum;
memset(pdbr_enumStrs,'\0',dbr_enumStrs_size);
switch(field_type) {
case DBF_ENUM:
if( prset && prset->get_enum_strs ) {
(*prset->get_enum_strs)(paddr,pdbr_enumStrs);
} else {
*options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
}
break;
case DBF_MENU:
pdbMenu = (dbMenu *)pdbFldDes->ftPvt;
no_str = pdbMenu->nChoice;
papChoice= pdbMenu->papChoiceValue;
goto choice_common;
case DBF_DEVICE:
pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt;
if(!pdbDeviceMenu) {
*options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
break;
}
no_str = pdbDeviceMenu->nChoice;
papChoice = pdbDeviceMenu->papChoice;
goto choice_common;
choice_common:
i = sizeof(pdbr_enumStrs->strs)/
sizeof(pdbr_enumStrs->strs[0]);
if(i<no_str) no_str = i;
pdbr_enumStrs->no_str = no_str;
ptemp = &(pdbr_enumStrs->strs[0][0]);
for (i=0; i<no_str; i++) {
if(papChoice[i]==NULL) *ptemp=0;
else {
strncpy(ptemp,papChoice[i],
sizeof(pdbr_enumStrs->strs[0]));
*(ptemp+sizeof(pdbr_enumStrs->strs[0])-1) = 0;
}
ptemp += sizeof(pdbr_enumStrs->strs[0]);
}
break;
default:
*options = (*options)^DBR_ENUM_STRS;/*Turn off option*/
break;
memset(penum, 0, dbr_enumStrs_size);
/* from this point
* on success, return early
* on failure, jump or fall through to clear *options bit.
*/
if(paddr->field_type == DBF_ENUM) {
if( prset && prset->get_enum_strs ) {
(*prset->get_enum_strs)(paddr,penum);
return;
}
} else if(paddr->field_type == DBF_MENU || paddr->field_type == DBF_DEVICE) {
char **ppchoices;
epicsUInt32 i, nchoices = 0;
if(paddr->field_type == DBF_MENU) {
dbMenu *pmenu = paddr->pfldDes->ftPvt;
nchoices = pmenu->nChoice;
ppchoices= pmenu->papChoiceValue;
} else if(paddr->field_type == DBF_DEVICE) {
dbDeviceMenu *pdevs = paddr->pfldDes->ftPvt;
if(!pdevs)
goto nostrs;
nchoices = pdevs->nChoice;
ppchoices = pdevs->papChoice;
}
if(nchoices > NELEMENTS(penum->strs))
nchoices = NELEMENTS(penum->strs); /* availible > capacity, truncated list */
penum->no_str = nchoices;
for(i=0; i<nchoices; i++) {
if(ppchoices[i]) {
strncpy(penum->strs[i], ppchoices[i],
sizeof(penum->strs[i]));
/* strs[i][] allowed to omit trailing nil */
} else {
penum->strs[i][0] = '\0';
}
}
*ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size;
return;
} else {
/* other DBF_* fall through to error */
}
nostrs:
/* indicate option data not available. distinct from no_str==0 */
*options = (*options)^DBR_ENUM_STRS;
}
static void get_graphics(DBADDR *paddr, char **ppbuffer,

View File

@@ -225,6 +225,7 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
assert(plink->type==CA_LINK);
pca = (caLink *)plink->value.pv_link.pvt;
caLinkInc(pca);
epicsMutexMustLock(pca->lock);
assert(!pca->monitor && !pca->connect && !pca->userPvt);
@@ -239,6 +240,8 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
dbScanUnlock(plink->precord);
epicsEventMustWait(evt);
/* ensure worker has finished executing */
dbCaSync();
dbScanLock(plink->precord);
epicsMutexMustLock(pca->lock);
@@ -250,6 +253,7 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
epicsEventDestroy(evt);
epicsMutexUnlock(pca->lock);
caLinkDec(pca);
dbScanUnlock(plink->precord);
}
@@ -287,16 +291,15 @@ void dbCaSync(void)
epicsEventMustWait(wake);
/* Worker holds workListLock when calling epicsEventMustTrigger()
* we cycle through workListLock to ensure worker call to
* we hold workListLock to ensure worker call to
* epicsEventMustTrigger() returns before we destroy the event.
*/
epicsMutexMustLock(workListLock);
epicsMutexUnlock(workListLock);
assert(templink.refcount==1);
epicsMutexDestroy(templink.lock);
epicsEventDestroy(wake);
epicsMutexUnlock(workListLock);
}
void dbCaCallbackProcess(void *userPvt)

View File

@@ -165,7 +165,7 @@ unsigned long dbChannelIO::nativeElementCount (
{
guard.assertIdenticalMutex ( this->mutex );
long elements = dbChannelElements ( this->dbch );
if ( elements >= 0u ) {
if ( elements >= 0 ) {
return static_cast < unsigned long > ( elements );
}
return 0u;

View File

@@ -15,13 +15,21 @@ typedef struct dbCommonPvt {
/* Thread which is currently processing this record */
struct epicsThreadOSD* procThread;
struct dbCommon common;
/* actually followed by:
* struct dbCommon common;
*/
} dbCommonPvt;
static EPICS_ALWAYS_INLINE
dbCommonPvt* dbRec2Pvt(struct dbCommon *prec)
{
return CONTAINER(prec, dbCommonPvt, common);
return (dbCommonPvt*)((char*)prec - sizeof(dbCommonPvt));
}
static EPICS_ALWAYS_INLINE
dbCommon* dbPvt2Rec(struct dbCommonPvt *pvt)
{
return (dbCommon*)&pvt[1];
}
#endif // DBCOMMONPVT_H

View File

@@ -94,7 +94,7 @@ static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
status = epicsParseFloat64(from, &dval, &end);
if (!status &&
dval >=0 &&
dval <= ULONG_MAX)
dval <= UINT_MAX)
*to = dval;
}
return status;

View File

@@ -302,7 +302,7 @@ static long getStringUlong(const dbAddr *paddr,
epicsFloat64 dval;
status = epicsParseFloat64(psrc, &dval, &end);
if (!status && 0 <= dval && dval <= ULONG_MAX)
if (!status && 0 <= dval && dval <= UINT_MAX)
*pdst = dval;
}
if (status)
@@ -1052,7 +1052,7 @@ static long putStringUlong(dbAddr *paddr,
epicsFloat64 dval;
status = epicsParseFloat64(psrc, &dval, &end);
if (!status && 0 <= dval && dval <= ULONG_MAX)
if (!status && 0 <= dval && dval <= UINT_MAX)
*pdst = dval;
}
if (status)

View File

@@ -7,20 +7,38 @@
* EPICS Base is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvertFast.h */
/** @file dbConvertFast.h
* @brief Data conversion for scalar values
*
* The typedef FASTCONVERTFUNC is defined in link.h as:
* @code
* long convert(const void *from, void *to, const struct dbAddr *paddr);
* @endcode
*
* The arrays declared here provide pointers to the fast conversion
* routine where the first array index is the data type for the first
* "from" pointer arg, and the second array index is the data type for
* the second "to" pointer arg. The array index values are a subset of
* the DBF_ enum values defined in dbFldTypes.h
*/
#ifndef INCdbConvertFasth
#define INCdbConvertFasth
#include "dbFldTypes.h"
#include "dbCoreAPI.h"
#include "link.h"
#ifdef __cplusplus
extern "C" {
#endif
DBCORE_API extern long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])();
DBCORE_API extern long (*dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1])();
/** Function pointers for get conversions */
DBCORE_API extern const FASTCONVERTFUNC
dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1];
/** Function pointers for put conversions */
DBCORE_API extern const FASTCONVERTFUNC
dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1];
#ifdef __cplusplus
}

View File

@@ -19,8 +19,6 @@
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
typedef long (*FASTCONVERT)();
typedef struct parseContext {
int depth;
short dbrType;
@@ -42,7 +40,7 @@ static int dbcj_boolean(void *ctx, int val) {
static int dbcj_integer(void *ctx, long long num) {
parseContext *parser = (parseContext *) ctx;
epicsInt64 val64 = num;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType];
FASTCONVERTFUNC conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType];
if (parser->elems > 0) {
conv(&val64, parser->pdest, NULL);
@@ -54,7 +52,7 @@ static int dbcj_integer(void *ctx, long long num) {
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
FASTCONVERTFUNC conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
if (parser->elems > 0) {
conv(&num, parser->pdest, NULL);

View File

@@ -98,8 +98,8 @@ struct event_user {
unsigned char extra_labor; /* if set call extra labor func */
unsigned char flowCtrlMode; /* replace existing monitor */
unsigned char extraLaborBusy;
void (*init_func)();
epicsThreadId init_func_arg;
void (*init_func)(void *);
void *init_func_arg;
};
typedef struct {

File diff suppressed because it is too large Load Diff

View File

@@ -133,7 +133,7 @@ void dbInitLink(struct link *plink, short dbfType)
plink->value.pv_link.pvlMask |= pvlOptFWD;
}
else {
errlogPrintf("Forward-link uses Channel Access "
errlogPrintf(ERL_WARNING ": Forward-link uses Channel Access "
"without pointing to PROC field\n"
" %s.%s => %s\n",
precord->name, dbLinkFieldName(plink),

View File

@@ -307,7 +307,7 @@ typedef struct lset {
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pbuffer where the data is
* @param nRequest number of elements to send
* @returns status value
*/
@@ -324,7 +324,7 @@ typedef struct lset {
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pbuffer where the data is
* @param nRequest number of elements to send
* @returns status value
*/

View File

@@ -918,7 +918,7 @@ long dblsr(char *recordname,int level)
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
pdbAddr = &((dbChannel *)(plink->value.pv_link.pvt))->addr;
printf("\t%s",pdbFldDes->name);
if(pdbFldDes->field_type==DBF_INLINK) {
printf("\t INLINK");

View File

@@ -155,7 +155,7 @@ void scanStop(void)
{
int i;
if (scanCtl == ctlExit) return;
if (scanCtl == ctlInit || scanCtl == ctlExit) return;
scanCtl = ctlExit;
interruptAccept = FALSE;
@@ -264,7 +264,7 @@ void scanAdd(struct dbCommon *precord)
} else if (scan == menuScanI_O_Intr) {
ioscan_head *piosh = NULL;
int prio;
DEVSUPFUN get_ioint_info;
long (*get_ioint_info)(int, struct dbCommon *, IOSCANPVT*);
if (precord->dset == NULL){
recGblRecordError(-1, (void *)precord,
@@ -332,7 +332,7 @@ void scanDelete(struct dbCommon *precord)
} else if (scan == menuScanI_O_Intr) {
ioscan_head *piosh = NULL;
int prio;
DEVSUPFUN get_ioint_info;
long (*get_ioint_info)(int, struct dbCommon *, IOSCANPVT*);
if (precord->dset==NULL) {
recGblRecordError(-1, (void *)precord,

View File

@@ -680,7 +680,7 @@ long dbtpf(const char *pname, const char *pvalue)
long dbior(const char *pdrvName,int interest_level)
{
drvSup *pdrvSup;
struct drvet *pdrvet;
drvet *pdrvet;
dbRecordType *pdbRecordType;
if (!pdbbase) {

View File

@@ -62,7 +62,7 @@ void recGblRecordError(long status, void *pdbc,
dbCommon *precord = pdbc;
char errMsg[256] = "";
if (status)
if ( status>0 )
errSymLookup(status, errMsg, sizeof(errMsg));
errlogPrintf("recGblRecordError: %s %s PV: %s\n",

View File

@@ -11,6 +11,8 @@
SRC_DIRS += $(IOCDIR)/dbStatic
USR_CFLAGS += -DUSE_TYPED_DRVET
INC += dbBase.h
INC += dbFldTypes.h
INC += dbStaticLib.h

View File

@@ -21,6 +21,7 @@
#include "dbDefs.h"
#include "recSup.h"
#include "devSup.h"
#include "drvSup.h"
typedef struct dbMenu {
ELLNODE node;
@@ -33,7 +34,7 @@ typedef struct dbMenu {
typedef struct drvSup {
ELLNODE node;
char *name;
struct drvet *pdrvet;
drvet *pdrvet;
}drvSup;
typedef struct devSup {
@@ -119,7 +120,7 @@ typedef struct dbRecordNode {
ELLLIST infoList; /*LIST head of info nodes*/
int flags;
/** Parse order of this record()
* @since UNRELEASED
* @since 7.0.8.1
*/
unsigned order;
struct dbRecordNode *aliasedRecnode; /* NULL unless flags|DBRN_FLAGS_ISALIAS */
@@ -189,7 +190,7 @@ typedef struct dbBase {
short ignoreMissingMenus;
short loadCdefs;
/** Total number of records.
* @since UNRELEASED
* @since 7.0.8.1
*/
unsigned no_records;
}dbBase;

View File

@@ -225,7 +225,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
char **macPairs;
if (ellCount(&tempList)) {
epicsPrintf("dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
}
if (getIocState() != iocVoid) {
@@ -250,7 +250,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
if (substitutions == NULL)
substitutions = "";
if(macCreateHandle(&macHandle,NULL)) {
epicsPrintf("macCreateHandle error\n");
fprintf(stderr, ERL_ERROR ": macCreateHandle failed\n");
status = -1;
goto cleanup;
}
@@ -294,7 +294,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
status = pvt_yy_parse();
if (ellCount(&tempList) && !yyAbort)
epicsPrintf("dbReadCOM: Parser stack dirty w/o error. %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty w/o error. %d\n", ellCount(&tempList));
while (ellCount(&tempList))
popFirstTemp(); /* Memory leak on parser failure */
@@ -401,15 +401,15 @@ static void dbIncludePrint(void)
inputFile *pinputFile = pinputFileNow;
while (pinputFile) {
epicsPrintf(" in");
fprintf(stderr, " in");
if (pinputFile->path)
epicsPrintf(" path \"%s\" ",pinputFile->path);
fprintf(stderr, " path \"%s\" ",pinputFile->path);
if (pinputFile->filename) {
epicsPrintf(" file \"%s\"",pinputFile->filename);
fprintf(stderr, " file \"%s\"",pinputFile->filename);
} else {
epicsPrintf(" standard input");
fprintf(stderr, " standard input");
}
epicsPrintf(" line %d\n",pinputFile->line_num);
fprintf(stderr, " line %d\n",pinputFile->line_num);
pinputFile = (inputFile *)ellPrevious(&pinputFile->node);
}
return;
@@ -434,7 +434,7 @@ static void dbIncludeNew(char *filename)
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp);
if (!fp) {
epicsPrintf("Can't open include file \"%s\"\n", filename);
fprintf(stderr, "Can't open include file \"%s\"\n", filename);
yyerror(NULL);
free((void *)pinputFile->filename);
free((void *)pinputFile);
@@ -696,7 +696,7 @@ static void dbRecordtypeEmpty(void)
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
epicsPrintf("Declaration of recordtype(%s) preceeded full definition.\n",
fprintf(stderr, "Declaration of recordtype(%s) preceeded full definition.\n",
pdbRecordType->name);
yyerrorAbort(NULL);
}
@@ -801,7 +801,7 @@ static void dbDevice(char *recordtype,char *linktype,
int i,link_type;
pgphentry = gphFind(savedPdbbase->pgpHash,recordtype,&savedPdbbase->recordTypeList);
if(!pgphentry) {
epicsPrintf("Record type \"%s\" not found for device \"%s\"\n",
fprintf(stderr, "Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
yyerror(NULL);
return;
@@ -814,7 +814,7 @@ static void dbDevice(char *recordtype,char *linktype,
}
}
if(link_type==-1) {
epicsPrintf("Bad link type \"%s\" for device \"%s\"\n",
fprintf(stderr, "Bad link type \"%s\" for device \"%s\"\n",
linktype, choicestring);
yyerror(NULL);
return;
@@ -1077,16 +1077,16 @@ int dbRecordNameValidate(const char *name)
if(i==0) {
/* first character restrictions */
if(c=='-' || c=='+' || c=='[' || c=='{') {
errlogPrintf("Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
fprintf(stderr, "Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
}
}
/* any character restrictions */
if(c < ' ') {
errlogPrintf("Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
fprintf(stderr, "Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
name, c);
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
epicsPrintf(ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
fprintf(stderr, ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
c, name);
yyerrorAbort(NULL);
return 1;
@@ -1113,15 +1113,29 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbFindRecord(pdbentry, name);
if (status == 0)
return; /* done */
epicsPrintf(ERL_ERROR ": Record \"%s\" not found\n", name);
fprintf(stderr, ERL_ERROR ": Record \"%s\" not found\n", name);
yyerror(NULL);
duplicate = TRUE;
return;
}
if (recordType[0] == '#' && recordType[1] == 0) {
status = dbFindRecord(pdbentry, name);
if (status == 0) {
dbDeleteRecord(pdbentry);
} else {
fprintf(stderr, ERL_WARNING ": Unable to delete record \"%s\". Not found.\n"
" at file %s line %d\n",
name, pinputFileNow->filename, pinputFileNow->line_num);
}
popFirstTemp();
dbFreeEntry(pdbentry);
duplicate = TRUE;
return;
}
status = dbFindRecordType(pdbentry, recordType);
if (status) {
epicsPrintf("Record \"%s\" is of unknown type \"%s\"\n",
fprintf(stderr, "Record \"%s\" is of unknown type \"%s\"\n",
name, recordType);
yyerrorAbort(NULL);
return;
@@ -1132,14 +1146,14 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbCreateRecord(pdbentry,name);
if (status == S_dbLib_recExists) {
if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) {
epicsPrintf(ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
fprintf(stderr, ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType);
yyerror(NULL);
duplicate = TRUE;
return;
}
else if (dbRecordsOnceOnly) {
epicsPrintf(ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
fprintf(stderr, ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
"Used record type \"*\" to append.\n",
name);
yyerror(NULL);
@@ -1147,7 +1161,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
}
}
else if (status) {
epicsPrintf("Can't create record \"%s\" of type \"%s\"\n",
fprintf(stderr, "Can't create record \"%s\" of type \"%s\"\n",
name, recordType);
yyerrorAbort(NULL);
}
@@ -1167,7 +1181,7 @@ static void dbRecordField(char *name,char *value)
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
if (status) {
epicsPrintf("%s Record \"%s\" does not have a field \"%s\"\n",
fprintf(stderr, "%s Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
if(dbGetRecordName(pdbentry)) {
DBENTRY temp;
@@ -1183,17 +1197,17 @@ static void dbRecordField(char *name,char *value)
}
dbFinishEntry(&temp);
if(bestSim>0.0) {
epicsPrintf(" Did you mean \"%s\"?", bestFld->name);
fprintf(stderr, " Did you mean \"%s\"?", bestFld->name);
if(bestFld->prompt)
epicsPrintf(" (%s)", bestFld->prompt);
epicsPrintf("\n");
fprintf(stderr, " (%s)", bestFld->prompt);
fprintf(stderr, "\n");
}
}
yyerror(NULL);
return;
}
if (pdbentry->indfield == 0) {
epicsPrintf("Can't set \"NAME\" field of record \"%s\"\n",
fprintf(stderr, "Can't set \"NAME\" field of record \"%s\"\n",
dbGetRecordName(pdbentry));
yyerror(NULL);
return;
@@ -1211,7 +1225,7 @@ static void dbRecordField(char *name,char *value)
char msg[128];
errSymLookup(status, msg, sizeof(msg));
epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s : %s\n",
fprintf(stderr, "Can't set \"%s.%s\" to \"%s\" %s : %s\n",
dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg);
dbPutStringSuggest(pdbentry, value);
yyerror(NULL);
@@ -1242,31 +1256,57 @@ static void dbRecordInfo(char *name, char *value)
status = dbPutInfo(pdbentry,name,value);
if (status) {
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
fprintf(stderr, "Can't set \"%s\" info \"%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
yyerror(NULL);
return;
}
}
static long createAlias(DBENTRY *pdbentry, const char *alias)
{
DBENTRY tempEntry;
long status;
dbRecordNode *precnode = pdbentry->precnode;
if (precnode->aliasedRecnode) precnode = precnode->aliasedRecnode;
dbInitEntry(pdbentry->pdbbase, &tempEntry);
status = dbFindRecord(&tempEntry, alias);
if (status == 0) {
if (tempEntry.precnode->aliasedRecnode != precnode) {
if (tempEntry.precnode->aliasedRecnode)
fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by an alias for \"%s\"\n",
alias, dbGetRecordName(pdbentry),
tempEntry.precnode->aliasedRecnode->recordname);
else
fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by a record\n",
alias, dbGetRecordName(pdbentry));
status = S_dbLib_recExists;
} else if (dbRecordsOnceOnly) {
fprintf(stderr, ERL_ERROR ": Alias \"%s\" already defined and dbRecordsOnceOnly set.\n",
alias);
status = S_dbLib_recExists;
}
} else {
status = dbCreateAlias(pdbentry, alias);
}
dbFinishEntry(&tempEntry);
return status;
}
static void dbRecordAlias(char *name)
{
DBENTRY *pdbentry;
tempListNode *ptempListNode;
long status;
if(dbRecordNameValidate(name))
return;
if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbCreateAlias(pdbentry, name);
if (status) {
epicsPrintf("Can't create alias \"%s\" for \"%s\"\n",
name, dbGetRecordName(pdbentry));
if (createAlias(pdbentry, name) != 0) {
yyerror(NULL);
return;
}
}
@@ -1280,13 +1320,11 @@ static void dbAlias(char *name, char *alias)
dbInitEntry(savedPdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
fprintf(stderr, "Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);
yyerror(NULL);
}
else if (dbCreateAlias(pdbEntry, alias)) {
epicsPrintf("Can't create alias \"%s\" referring to \"%s\"\n",
alias, name);
else if (createAlias(pdbEntry, alias) != 0) {
yyerror(NULL);
}
dbFinishEntry(pdbEntry);

View File

@@ -1219,7 +1219,9 @@ long dbNextRecordType(DBENTRY *pdbentry)
char * dbGetRecordTypeName(DBENTRY *pdbentry)
{
return(pdbentry->precordType->name);
dbRecordType *pdbRecordType = pdbentry->precordType;
if(!pdbRecordType) return NULL;
return(pdbRecordType->name);
}
int dbGetNRecordTypes(DBENTRY *pdbentry)
@@ -1477,6 +1479,17 @@ long dbDeleteAliases(DBENTRY *pdbentry)
return 0;
}
static void dbDeleteRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
{
short i;
for (i=0; i<rtyp->no_links; i++) {
dbFldDes *pflddes = rtyp->papFldDes[rtyp->link_ind[i]];
DBLINK *plink = (DBLINK *)(((char *)prec) + pflddes->offset);
dbFreeLinkContents(plink);
}
}
long dbDeleteRecord(DBENTRY *pdbentry)
{
dbBase *pdbbase = pdbentry->pdbbase;
@@ -1492,6 +1505,7 @@ long dbDeleteRecord(DBENTRY *pdbentry)
preclist = &precordType->recList;
ellDelete(preclist, &precnode->node);
dbPvdDelete(pdbbase, precnode);
dbDeleteRecordLinks(precordType, precnode->precord);
while (!dbFirstInfo(pdbentry)) {
dbDeleteInfo(pdbentry);
}
@@ -2204,12 +2218,14 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
*/
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %s)\n",
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %s with \"%s\" (type %s)\n",
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue,
plink->text, pamaplinkType[link_info.ltype].strvalue);
} else if(dbSetLink(plink, &link_info, devsup)) {
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %s)\n",
prec->name, pflddes->name, plink->type, plink->text, pamaplinkType[link_info.ltype].strvalue);
errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %s with \"%s\" (type %s)\n",
prec->name, pflddes->name, pamaplinkType[plink->type].strvalue,
plink->text, pamaplinkType[link_info.ltype].strvalue);
}
free(plink->text);
plink->text = NULL;

View File

@@ -66,7 +66,17 @@ void devExtend(dsxt *pdsxt)
pthisDevSup->pdsxt = pdsxt;
}
}
/* Ensure that: sizeof(dbCommonPvt) + pdbRecordType->rec_size
* accounts for necessary alignment of record type struct
*/
typedef struct {
dbCommonPvt prefix;
/* ensure no padding needed... */
dbCommon suffix;
} dbCommonPvtAlignmentTest;
STATIC_ASSERT(offsetof(dbCommonPvtAlignmentTest, suffix)==sizeof(dbCommonPvt));
long dbAllocRecord(DBENTRY *pdbentry,const char *precordName)
{
dbRecordType *pdbRecordType = pdbentry->precordType;
@@ -90,8 +100,8 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName)
precordName, pdbRecordType->name, pdbRecordType->rec_size);
return(S_dbLib_noRecSup);
}
ppvt = dbCalloc(1, offsetof(dbCommonPvt, common) + pdbRecordType->rec_size);
precord = &ppvt->common;
ppvt = dbCalloc(1, sizeof(dbCommonPvt) + pdbRecordType->rec_size);
precord = dbPvt2Rec(ppvt);
ppvt->recnode = precnode;
precord->rdes = pdbRecordType;
precnode->precord = precord;

View File

@@ -8,7 +8,7 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
%{
static int yyerror();
static int yyerror(char *str);
static int yy_start;
static long pvt_yy_parse(void);
static int yyFailed = 0;
@@ -370,14 +370,15 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); }
static int yyerror(char *str)
{
if (str)
epicsPrintf(ERL_ERROR ": %s\n", str);
fprintf(stderr, ERL_ERROR ": %s\n", str);
else
epicsPrintf(ERL_ERROR "");
fprintf(stderr, ERL_ERROR ": ");
if (!yyFailed) { /* Only print this stuff once */
epicsPrintf(" at or before '%s'", yytext);
fprintf(stderr, " at or before '%s'", yytext);
dbIncludePrint();
yyFailed = TRUE;
}
fprintf(stderr, "\n %d | %s\n", pinputFileNow->line_num, my_buffer);
return(0);
}
static long pvt_yy_parse(void)

View File

@@ -77,14 +77,14 @@ struct macro_link {
char *macroStr;
};
struct dbCommon;
typedef long (*LINKCVT)();
struct dbAddr;
typedef long (*FASTCONVERTFUNC)(const void *from, void *to, const struct dbAddr *paddr);
struct pv_link {
ELLNODE backlinknode;
char *pvname; /* pvname link points to */
void *pvt; /* CA or DB private */
LINKCVT getCvt; /* input conversion function */
FASTCONVERTFUNC getCvt; /* input conversion function */
short pvlMask; /* Options mask */
short lastGetdbrType; /* last dbrType for DB or CA get */
};
@@ -188,8 +188,8 @@ union value {
struct vxiio vxiio; /* vxi io */
};
struct dbCommon;
struct lset;
struct link {
struct dbCommon *precord; /* Pointer to record owning link */
short type;

View File

@@ -14,7 +14,6 @@ SRC_DIRS += $(IOCDIR)/dbtemplate
PROD_CMD += msi
msi_SRCS = msi.cpp
msi_LIBS += Com
HTMLS += msi.html
INC += dbLoadTemplate.h

View File

@@ -114,7 +114,7 @@ int iocInit(void)
static int iocBuild_1(void)
{
if (iocState != iocVoid) {
errlogPrintf("iocBuild: IOC can only be initialized from uninitialized or stopped state\n");
errlogPrintf("iocBuild: " ERL_ERROR " IOC can only be initialized from uninitialized or stopped state\n");
return -1;
}
errlogInit(0);
@@ -126,7 +126,7 @@ static int iocBuild_1(void)
errlogPrintf("Starting iocInit\n");
if (checkDatabase(pdbbase)) {
errlogPrintf("iocBuild: Aborting, bad database definition (DBD)!\n");
errlogPrintf("iocBuild: " ERL_ERROR " Aborting, bad database definition (DBD)!\n");
return -1;
}
epicsSignalInstallSigHupIgnore();
@@ -237,7 +237,7 @@ int iocBuildIsolated(void)
int iocRun(void)
{
if (iocState != iocPaused && iocState != iocBuilt) {
errlogPrintf("iocRun: IOC not paused\n");
errlogPrintf("iocRun: " ERL_WARNING " IOC not paused\n");
return -1;
}
initHookAnnounce(initHookAtIocRun);
@@ -268,7 +268,7 @@ int iocRun(void)
int iocPause(void)
{
if (iocState != iocRunning) {
errlogPrintf("iocPause: IOC not running\n");
errlogPrintf("iocPause: " ERL_WARNING " IOC not running\n");
return -1;
}
initHookAnnounce(initHookAtIocPause);
@@ -306,59 +306,59 @@ static int checkDatabase(dbBase *pdbbase)
const dbMenu *pMenu;
if (!pdbbase) {
errlogPrintf("checkDatabase: No database definitions loaded.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " No database definitions loaded.\n");
return -1;
}
pMenu = dbFindMenu(pdbbase, "menuConvert");
if (!pMenu) {
errlogPrintf("checkDatabase: menuConvert not defined.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvert not defined.\n");
return -1;
}
if (pMenu->nChoice <= menuConvertLINEAR) {
errlogPrintf("checkDatabase: menuConvert has too few choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvert has too few choices.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertNO_CONVERSION],
"menuConvertNO_CONVERSION")) {
errlogPrintf("checkDatabase: menuConvertNO_CONVERSION doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertNO_CONVERSION doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertSLOPE], "menuConvertSLOPE")) {
errlogPrintf("checkDatabase: menuConvertSLOPE doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertSLOPE doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertLINEAR], "menuConvertLINEAR")) {
errlogPrintf("checkDatabase: menuConvertLINEAR doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertLINEAR doesn't match.\n");
return -1;
}
pMenu = dbFindMenu(pdbbase, "menuScan");
if (!pMenu) {
errlogPrintf("checkDatabase: menuScan not defined.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan not defined.\n");
return -1;
}
if (pMenu->nChoice <= menuScanI_O_Intr) {
errlogPrintf("checkDatabase: menuScan has too few choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan has too few choices.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanPassive],
"menuScanPassive")) {
errlogPrintf("checkDatabase: menuScanPassive doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanPassive doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanEvent],
"menuScanEvent")) {
errlogPrintf("checkDatabase: menuScanEvent doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanEvent doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanI_O_Intr],
"menuScanI_O_Intr")) {
errlogPrintf("checkDatabase: menuScanI_O_Intr doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanI_O_Intr doesn't match.\n");
return -1;
}
if (pMenu->nChoice <= SCAN_1ST_PERIODIC) {
errlogPrintf("checkDatabase: menuScan has no periodic choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan has no periodic choices.\n");
return -1;
}
@@ -388,7 +388,7 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
for (pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); pdrvSup;
pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
struct drvet *pdrvet = registryDriverSupportFind(pdrvSup->name);
drvet *pdrvet = registryDriverSupportFind(pdrvSup->name);
if (!pdrvet) {
errlogPrintf("iocInit: driver %s not found\n", pdrvSup->name);

View File

@@ -9,7 +9,9 @@
#include <set>
#include <map>
#include <stdint.h>
#include <string.h>
#include <stdint.h>
#define EPICS_PRIVATE_API
@@ -32,11 +34,12 @@ namespace {
struct compareLoc {
bool operator()(const recordTypeLocation& lhs, const recordTypeLocation& rhs) const
{
if(lhs.prset<rhs.prset)
if (lhs.prset < rhs.prset)
return true;
else if(lhs.prset>rhs.prset)
if (lhs.prset > rhs.prset)
return false;
return lhs.sizeOffset<rhs.sizeOffset;
return reinterpret_cast<uintptr_t>(lhs.sizeOffset)
< reinterpret_cast<uintptr_t>(rhs.sizeOffset);
}
};

View File

@@ -65,7 +65,7 @@ void registerDevices(DBBASE *pbase, int nDevices,
}
void registerDrivers(DBBASE *pbase, int nDrivers,
const char * const * driverSupportNames, struct drvet * const *drvsl)
const char * const * driverSupportNames, drvet * const *drvsl)
{
int i;
for (i = 0; i < nDrivers; i++) {

View File

@@ -29,7 +29,7 @@ DBCORE_API void registerDevices(
const char * const *deviceSupportNames, const dset * const *devsl);
DBCORE_API void registerDrivers(
DBBASE *pbase, int nDrivers,
const char * const *driverSupportNames, struct drvet * const *drvsl);
const char * const *driverSupportNames, drvet * const *drvsl);
DBCORE_API void registerJLinks(
DBBASE *pbase, int nDrivers, jlif * const *jlifsl);

View File

@@ -18,12 +18,12 @@ static void *registryID = "driver support";
DBCORE_API int registryDriverSupportAdd(
const char *name, struct drvet *pdrvet)
const char *name, drvet *pdrvet)
{
return registryAdd(registryID, name, pdrvet);
}
DBCORE_API struct drvet * registryDriverSupportFind(
DBCORE_API drvet * registryDriverSupportFind(
const char *name)
{
return registryFind(registryID, name);

View File

@@ -19,8 +19,8 @@ extern "C" {
#endif
DBCORE_API int registryDriverSupportAdd(
const char *name, struct drvet *pdrvet);
DBCORE_API struct drvet * registryDriverSupportFind(
const char *name, drvet *pdrvet);
DBCORE_API drvet * registryDriverSupportFind(
const char *name);
#ifdef __cplusplus

View File

@@ -120,6 +120,11 @@ static void req_server (void *pParm)
}
}
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
taskwdRemove(0);
}
static
@@ -585,8 +590,7 @@ void rsrv_init (void)
errlogPrintf ( "cas " ERL_WARNING ": reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
}
epicsSnprintf(buf, sizeof(buf)-1u, "%u", ca_server_port);
buf[sizeof(buf)-1u] = '\0';
epicsSnprintf(buf, sizeof(buf), "%u", ca_server_port);
epicsEnvSet("RSRV_SERVER_PORT", buf);
}
@@ -748,6 +752,7 @@ void rsrv_init (void)
if(!havesometcp)
cantProceed("CAS: No TCP server started\n");
}
free(socks);
/* servers list is considered read-only from this point */

View File

@@ -98,13 +98,10 @@ static void clean_addrq(struct client *client)
}
epicsMutexUnlock ( client->chanListLock );
# ifdef DEBUG
if(ndelete){
if (CASDEBUG>1 && ndelete){
epicsPrintf ("CAS: %d CA channels have expired after %f sec\n",
ndelete, maxdelay);
}
# endif
}
/*

View File

@@ -129,7 +129,11 @@ void rsrv_online_notify_task(void *pParm)
}
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
free(lastError);
taskwdRemove(0);
}

View File

@@ -36,8 +36,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct calc_link {
jlink jlink; /* embedded object */
int nArgs;
@@ -558,7 +556,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;
@@ -638,7 +636,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;

View File

@@ -23,8 +23,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct const_link {
jlink jlink; /* embedded object */
int nElems;
@@ -458,7 +456,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
short dbrSize;
char *pdest = pbuffer;
int nElems = clink->nElems;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
long status;
if(INVALID_DB_REQ(dbrType))
@@ -495,9 +493,11 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
}
else {
/* Long string conversion */
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq] = 0;
nElems = strlen(pbuffer) + 1;
if (*pnReq > 0) {
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq - 1] = 0;
nElems = strlen(pbuffer) + 1;
}
status = 0;
}
break;

View File

@@ -34,8 +34,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct state_link {
jlink jlink; /* embedded object */
char *name;
@@ -143,7 +141,7 @@ static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer,
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;

View File

@@ -16,7 +16,7 @@ has a number of additional features:
=item *
It provides 20 different input and output fields which can hold array or
It provides 21 different input and output fields which can hold array or
scalar values.
The types and array capacities of these are user configurable, and they all
have an associated input or output link.

View File

@@ -1160,7 +1160,7 @@ See next section.
=head2 C<special>
This is called id CALC or OCAL is changed. C<special> calls postfix.
This is called if CALC or OCAL is changed. C<special> calls postfix.
=head2 C<get_units>

View File

@@ -149,13 +149,16 @@ static int compare(const void *arg1, const void *arg2)
else return 1;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
static int compress_array(compressRecord *prec,
double *psource, int no_elements)
{
epicsInt32 i,j;
epicsInt32 j;
epicsInt32 n, nnew;
epicsInt32 nsam = prec->nsam;
double value;
epicsUInt32 samples_written = 0;
double value = 0.0;
/* skip out of limit data */
if (prec->ilil < prec->ihil) {
@@ -167,61 +170,54 @@ static int compress_array(compressRecord *prec,
}
if (prec->n <= 0)
prec->n = 1;
if (no_elements < prec->n && prec->pbuf != menuYesNoYES)
return 1; /*dont do anything*/
n = no_elements;
n = prec->n;
/* determine number of samples to take */
if (no_elements < nsam * n)
nnew = (no_elements / n);
else nnew = nsam;
nnew = min(no_elements, nsam * n);
/* compress according to specified algorithm */
switch (prec->alg){
case compressALG_N_to_1_Low_Value:
/* compress N to 1 keeping the lowest value */
for (i = 0; i < nnew; i++) {
while (nnew > 0)
{
if (nnew < n && prec->pbuf != menuYesNoYES)
break;
n = min(n, nnew);
switch (prec->alg)
{
case compressALG_N_to_1_Low_Value:
value = *psource++;
for (j = 1; j < n; j++, psource++) {
for (j = 1; j < n; j++, psource++)
{
if (value > *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_High_Value:
/* compress N to 1 keeping the highest value */
for (i = 0; i < nnew; i++){
break;
case compressALG_N_to_1_High_Value:
value = *psource++;
for (j = 1; j < n; j++, psource++) {
for (j = 1; j < n; j++, psource++)
{
if (value < *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Average:
/* compress N to 1 keeping the average value */
for (i = 0; i < nnew; i++) {
value = 0;
for (j = 0; j < n; j++, psource++)
break;
case compressALG_N_to_1_Average:
value = *psource++;
for (j = 1; j < n; j++, psource++)
{
value += *psource;
value /= n;
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Median:
/* compress N to 1 keeping the median value */
/* note: sorts source array (OK; it's a work pointer) */
for (i = 0; i < nnew; i++, psource += nnew) {
}
value = value / n;
break;
case compressALG_N_to_1_Median:
/* note: sorts source array (OK; it's a work pointer) */
qsort(psource, n, sizeof(double), compare);
value = psource[n / 2];
put_value(prec, &value, 1);
psource += n;
break;
}
break;
nnew -= n;
put_value(prec, &value, 1);
samples_written++;
}
return 0;
return (samples_written == 0);
}
static int array_average(compressRecord *prec,

View File

@@ -91,10 +91,10 @@ The BPTR field contains a pointer to the unsigned long array of frequency
values. The VAL field references this array as well. However, the BPTR field is
not accessible at run-time.
The MCNT field keeps counts the number of signal counts since the last monitor
The MCNT field keeps the number of signal counts since the last monitor
was invoked.
The collections controls field (CMD) is a menu field with five choices:
The collections controls field (CMD) is a menu field with four choices:
=menu histogramCMD
@@ -110,8 +110,6 @@ array. Unlike C<Read>, it doesn't clear the array first.
The C<Stop> command disables the reading of signal values into the array.
The C<Setup> command waits until the C<start> or C<read> command has been issued
to start counting.
The CSTA or collections status field implements the CMD field choices by
enabling or disabling the reading of values into the histogram array. While

View File

@@ -49,6 +49,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "lsi::init_record");

View File

@@ -9,7 +9,7 @@
=title Long String Input Record (lsi)
The long string input record is used to retrieve an arbitrary ASCII string with
a maximum length of 65535 characters.
a maximum length of 32767 characters.
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
@@ -36,7 +36,7 @@ from. It can be a database or channel access link, or a constant. If constant,
the VAL field is initialized with the constant and can be changed via dbPuts.
Otherwise, the string is read from the specified location each time the record
is processed and placed in the VAL field. The maximum number of characters in
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
VAL is given by SIZV, and cannot be larger than 32767. In addition, the
appropriate device support module must be entered into the DTYP field.
=fields VAL, OVAL, SIZV, INP, DTYP

View File

@@ -53,6 +53,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "lso::init_record");

View File

@@ -9,7 +9,7 @@
=title Long String Output Record (lso)
The long string output record is used to write an arbitrary ASCII string with a
maximum length of 65535 characters.
maximum length of 32767 characters.
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
@@ -41,7 +41,7 @@ C<supervisory> is specified, DOL is ignored, the current value of VAL is
written, and VAL can be changed externally via dbPuts at run-time.
The maximum number of characters in VAL is given by SIZV, and cannot be larger
than 65535.
than 32767.
DOL can also be a constant instead of a link, in which case VAL is initialized
to the constant value. Most simple string constants are likely to be interpreted

View File

@@ -337,6 +337,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "printf::init_record");

View File

@@ -152,7 +152,7 @@ Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Dat
for information on specifying links.
The formatted string is written to the VAL field. The maximum number of
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
characters in VAL is given by SIZV, and cannot be larger than 32767. The LEN
field contains the length of the formatted string in the VAL field.
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN

View File

@@ -17,10 +17,12 @@
#include <epicsGetopt.h>
#include "registryFunction.h"
#include "errlog.h"
#include "epicsThread.h"
#include "epicsExit.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "errlog.h"
#include "dbStaticLib.h"
#include "subRecord.h"
#include "dbAccess.h"
@@ -92,7 +94,7 @@ void usage(const char *arg0, const std::string& base_dbd) {
"interactive IOC shell.\n"
"\n"
"Compiled-in path to softIoc.dbd is:\n"
"\t"<<base_dbd.c_str()<<"\n";
"\t"<<base_dbd.c_str()<<std::endl;
}
void errIf(int ret, const std::string& msg)
@@ -239,7 +241,9 @@ int main(int argc, char *argv[])
if (loadedDb) {
if (verbose)
std::cout<<"iocInit()\n";
iocInit();
if(iocInit()) {
std::cerr<<ERL_ERROR " during iocInit()"<<std::endl;
}
epicsThreadSleep(0.2);
}
@@ -270,7 +274,8 @@ int main(int argc, char *argv[])
return 0;
}catch(std::exception& e){
std::cerr<<"Error: "<<e.what()<<"\n";
errlogFlush();
std::cerr<<ERL_ERROR ": "<<e.what()<<"\n";
epicsExit(2);
return 2;
}

View File

@@ -36,6 +36,7 @@ dbTestIoc_DBD += xLink.dbd
dbTestIoc_DBD += devx.dbd
dbTestIoc_DBD += jlinkz.dbd
dbTestIoc_DBD += dbLinkdset.dbd
dbTestIoc_DBD += dbCore.dbd
TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db
testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp
@@ -183,6 +184,12 @@ testHarness_SRCS += dbStaticTest.c
TESTFILES += ../dbStaticTest.db
TESTFILES += ../dbStaticTestAlias1.db
TESTFILES += ../dbStaticTestAlias2.db
TESTFILES += ../dbStaticTestAliasAgain1.db
TESTFILES += ../dbStaticTestAliasAgain2.db
TESTFILES += ../dbStaticTestAliasAgain3.db
TESTFILES += ../dbStaticTestAliasAgainError1.db
TESTFILES += ../dbStaticTestAliasAgainError2.db
TESTFILES += ../dbStaticTestRemove.db
TESTS += dbStaticTest
# This runs all the test programs in a known working order:

View File

@@ -82,12 +82,12 @@ void checkDoubleGet(dbChannel *chan, db_field_log* pfl)
testOk1(meta.status==UDF_ALARM);
testOk1(meta.acks==MAJOR_ALARM);
testOk1(meta.ackt==1);
testOk1(strncmp(meta.amsg, "oops", DB_UNITS_SIZE)==0);
testOk1(strncmp(meta.amsg, "oops", sizeof(meta.amsg))==0);
testOk1(meta.time.secPastEpoch==0x12345678);
testOk1(meta.time.nsec==0x90abcdef);
testOk1(meta.utag==0x10203040);
testOk1(meta.precision.dp==0x12345678);
testOk1(strncmp(meta.units, "arbitrary", DB_UNITS_SIZE)==0);
testOk1(strncmp(meta.units, "arbitrary", sizeof(meta.units))==0);
#define limitEq(UL, FL, VAL) testOk(meta.UL ## _ ## FL ## _limit == (VAL), #UL "_" #FL "_limit (%f) == %f", meta.UL ## _ ## FL ## _limit, VAL)
limitEq(lower, disp, 10000000.0-1.0);
limitEq(upper, disp, 10000000.0+1.0);
@@ -114,6 +114,8 @@ void testdbMetaDoubleGet(void)
STATIC_ASSERT(sizeof(meta.amsg)==sizeof(prec->amsg));
STATIC_ASSERT(sizeof(meta.amsg)==sizeof(pfl->amsg));
testDiag("testdbMetaDoubleGet");
if(!chan)
testAbort("Missing recmeta OTST");
if((status=dbChannelOpen(chan))!=0)
@@ -163,6 +165,8 @@ typedef struct {
DBRenumStrs
} dbMetaEnum;
enum {dbMetaMetaMask = DBR_STATUS | DBR_AMSG | DBR_ENUM_STRS | DBR_TIME | DBR_UTAG};
static
void testdbMetaEnumSizes(void)
{
@@ -189,6 +193,66 @@ void testdbMetaEnumSizes(void)
testOk(sizeof(dbMetaEnum)==pos, "sizeof(dbMetaEnum), %u == %u", (unsigned)sizeof(dbMetaEnum), (unsigned)pos);
}
static
void checkEnumGet(dbChannel *chan, db_field_log* pfl)
{
dbMetaEnum meta;
long options = (long)dbMetaMetaMask;
long nReq = 0;
long status;
/* spoil */
meta.no_str = -1;
meta.strs[0][0] = '!';
status=dbChannelGet(chan, DBF_DOUBLE, &meta, &options, &nReq, pfl);
testOk(status==0, "dbGet OTST : %ld", status);
testOk1(meta.severity==INVALID_ALARM);
testOk1(meta.status==UDF_ALARM);
testOk1(meta.acks==MAJOR_ALARM);
testOk1(meta.ackt==1);
testOk1(strncmp(meta.amsg, "oops", sizeof(meta.amsg))==0);
testOk1(meta.time.secPastEpoch==0x12345678);
testOk1(meta.time.nsec==0x90abcdef);
testOk1(meta.utag==0x10203040);
if(testOk1(meta.no_str==3)) {
testOk1(strncmp(meta.strs[0], "Before", sizeof(meta.strs[0]))==0);
testOk1(strncmp(meta.strs[1], "After", sizeof(meta.strs[0]))==0);
testOk1(strncmp(meta.strs[2], "None", sizeof(meta.strs[0]))==0);
}
}
void testdbMetaEnumGet(void)
{
long status;
xRecord* prec = (xRecord*)testdbRecordPtr("recmeta");
dbChannel *chan = dbChannelCreate("recmeta.SFX");
testDiag("testdbMetaEnumGet");
if(!chan)
testAbort("Missing recmeta SFX");
if((status=dbChannelOpen(chan))!=0)
testAbort("can't open recmeta SFX : %ld", status);
dbScanLock((dbCommon*)prec);
/* ensure that all meta-data has different non-zero values */
prec->otst = 10000000.0;
prec->sevr = INVALID_ALARM;
prec->stat = UDF_ALARM;
strcpy(prec->amsg, "oops");
prec->acks = MAJOR_ALARM;
prec->time.secPastEpoch = 0x12345678;
prec->time.nsec = 0x90abcdef;
prec->utag = 0x10203040;
testDiag("dbGet directly from record");
checkEnumGet(chan, NULL);
dbScanUnlock((dbCommon*)prec);
}
static
void testdbGetStringEqual(const char *pv, const char *expected)
{
@@ -347,7 +411,7 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(dbPutGet)
{
testPlan(124);
testPlan(137);
testdbPrepare();
testdbMetaDoubleSizes();
@@ -366,6 +430,7 @@ MAIN(dbPutGet)
eltc(1);
testdbMetaDoubleGet();
testdbMetaEnumGet();
testLongLink();
testLongAttr();

View File

@@ -597,8 +597,12 @@ void testJLink(void)
testNumZ(6);
testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
testdbPutFieldOk("j1.PHAS", DBF_LONG, 0);
testdbPutFieldOk("j1.OUTP", DBF_STRING, "{z:{good:99}}");
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
testdbGetFieldEqual("j1.PHAS", DBF_LONG, 4);
testdbPutFieldOk("j1.OUTP", DBF_STRING, "");
testdbPutFieldOk("j2.TSEL", DBF_STRING, "{'z':{good:0}}");
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
@@ -701,7 +705,7 @@ void testTSEL(void)
MAIN(dbPutLinkTest)
{
testPlan(348);
testPlan(352);
testLinkParse();
testLinkFailParse();
testCADBSet();

View File

@@ -13,6 +13,37 @@
#include <dbStaticPvt.h>
#include <dbUnitTest.h>
#include <testMain.h>
#include <epicsString.h>
#include <iocsh.h>
static void testEntryRemoved(const char *pv)
{
DBENTRY entry;
testDiag("testEntryRemoved(\"%s\")", pv);
dbInitEntry(pdbbase, &entry);
testOk(dbFindRecord(&entry, pv)==S_dbLib_recNotFound,
"Record '%s' not present", pv);
dbFinishEntry(&entry);
}
static void testEntryPresent(const char *pv)
{
DBENTRY entry;
testDiag("testEntryPresent(\"%s\")", pv);
dbInitEntry(pdbbase, &entry);
testOk(dbFindRecord(&entry, pv)==0,
"Record '%s' present", pv);
dbFinishEntry(&entry);
}
static void testEntry(const char *pv)
{
@@ -291,16 +322,19 @@ static void testDbVerify(const char *record)
dbFinishEntry(&entry);
}
static void testWrongAliasRecord(const char *filename)
static void testReadDatabase(const char *filename, int expectToFail)
{
FILE *fp = NULL;
long status;
dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR "..");
dbOpenFile(pdbbase, filename, &fp);
if(!fp) {
testAbort("Unable to read %s", filename);
testAbort("Unable to open %s", filename);
}
testOk(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL) != 0,
"Wrong alias record in %s is expected to fail", filename);
status = dbReadDatabaseFP(&pdbbase, fp, NULL, NULL);
testOk(!status == !expectToFail,
"Reading %s%s", filename,
expectToFail ? " is expected to fail" : "");
}
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
@@ -308,9 +342,10 @@ void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(dbStaticTest)
{
const char *ldir;
char *ldirDup;
FILE *fp = NULL;
testPlan(312);
testPlan(350);
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
@@ -320,13 +355,40 @@ MAIN(dbStaticTest)
if(!fp) {
testAbort("Unable to read dbStaticTest.db");
}
ldirDup = epicsStrDup(ldir);
if(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL)) {
testAbort("Unable to load %s%sdbStaticTest.db",
ldir, OSI_PATH_LIST_SEPARATOR);
ldirDup, OSI_PATH_LIST_SEPARATOR);
}
free(ldirDup);
testWrongAliasRecord("dbStaticTestAlias1.db");
testWrongAliasRecord("dbStaticTestAlias2.db");
dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR "..");
ldir = dbOpenFile(pdbbase, "dbStaticTestRemove.db", &fp);
if(!fp) {
testAbort("Unable to read dbStaticTestRemove.db");
}
ldirDup = epicsStrDup(ldir);
if(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL)) {
testAbort("Unable to load %s%sdbStaticTestRemove.db",
ldirDup, OSI_PATH_LIST_SEPARATOR);
}
free(ldirDup);
testReadDatabase("dbStaticTestAlias1.db", 1);
testReadDatabase("dbStaticTestAlias2.db", 1);
/* Test re-defining aliases */
testReadDatabase("dbStaticTestAliasAgain1.db", 0);
testReadDatabase("dbStaticTestAliasAgain1.db", 0);
testReadDatabase("dbStaticTestAliasAgain2.db", 0);
testReadDatabase("dbStaticTestAliasAgain2.db", 0);
testReadDatabase("dbStaticTestAliasAgain3.db", 0);
testReadDatabase("dbStaticTestAliasAgain3.db", 0);
testReadDatabase("dbStaticTestAliasAgainError1.db", 1);
testReadDatabase("dbStaticTestAliasAgainError2.db", 1);
iocshCmd("var dbRecordsOnceOnly 1");
testReadDatabase("dbStaticTestAliasAgain2.db", 1);
testReadDatabase("dbStaticTestAliasAgain3.db", 1);
testEntry("testrec.VAL");
testEntry("testalias.VAL");
@@ -341,6 +403,21 @@ MAIN(dbStaticTest)
testRec2Entry("testalias2");
testRec2Entry("testalias3");
testEntryPresent("testdelrec");
testEntryPresent("testdelrec6");
testEntryPresent("testdelalias66");
testEntryRemoved("testdelrec1");
testEntryRemoved("testdelrec2");
testEntryRemoved("testdelrec3");
testEntryRemoved("testdelrec4");
testEntryRemoved("testdelrec5");
testEntryRemoved("testdelalias6");
testEntryRemoved("testdelrec7");
testEntryRemoved("testdelalias7");
testEntryRemoved("testdelalias77");
testEntryRemoved("testdelrec8");
testEntryRemoved("testdelrec11");
eltc(0);
testIocInitOk();
eltc(1);
@@ -358,6 +435,21 @@ MAIN(dbStaticTest)
testRec2Entry("testalias2");
testRec2Entry("testalias3");
testEntryPresent("testdelrec");
testEntryPresent("testdelrec6");
testEntryPresent("testdelalias66");
testEntryRemoved("testdelrec1");
testEntryRemoved("testdelrec2");
testEntryRemoved("testdelrec3");
testEntryRemoved("testdelrec4");
testEntryRemoved("testdelrec5");
testEntryRemoved("testdelalias6");
testEntryRemoved("testdelrec7");
testEntryRemoved("testdelalias7");
testEntryRemoved("testdelalias77");
testEntryRemoved("testdelrec8");
testEntryRemoved("testdelrec11");
testDbVerify("testrec");
testIocShutdownOk();

View File

@@ -0,0 +1,4 @@
# Test re-load alias in record
record(x, "testrecAgain") {
alias("testaliasAgain1")
}

View File

@@ -0,0 +1,2 @@
# Test re-load alias for record
alias("testrecAgain", "testaliasAgain2")

View File

@@ -0,0 +1,2 @@
# Test re-load alias for alias
alias("testaliasAgain2", "testaliasAgain3")

View File

@@ -0,0 +1,2 @@
# ERROR: alias using name of exising alias for different record
alias("testrec", "testaliasAgain1")

View File

@@ -0,0 +1,2 @@
# ERROR: alias using name of exising record fails
alias("testrecAgain", "testrec")

View File

@@ -0,0 +1,55 @@
record(x, "testdelrec") { }
record(x, "testdelrec1") { }
record(x, "testdelrec2") {
field("INP", "foobar")
}
record(x, "testdelrec3") {
info("foo", "bar")
}
record(x, "testdelrec4") {
field("INP", "testdelrec.VAL")
}
record(x, "testdelrec5") {
field("FLNK", "testdelrec.VAL")
}
record(x, "testdelrec6") { }
alias("testdelrec6", "testdelalias6")
alias("testdelrec6", "testdelalias66")
record(x, "testdelrec7") { }
alias("testdelrec7", "testdelalias7")
alias("testdelrec7", "testdelalias77")
record(x, "testdelrec8") {
field("INP", "{z:{good:1}}")
}
record("#", "no:such:record") { }
record("#", "also:non:existant") {
field(FOO, "5")
}
record("#", "testdelrec1") { }
record("#", "testdelrec2") {
field("INP", "foobar2")
}
record("#", "testdelrec3") {
field("INP", "foobar2")
field("VAL", "1")
}
record("#", "testdelrec4") { }
record("#", "testdelrec5") { }
record("#", "testdelalias6") { }
record("#", "testdelrec7") { }
record("#", "testdelrec8") { }
record("#", "testdelrec11") { }

View File

@@ -59,6 +59,9 @@ static unsigned int nrecords;
#define MAXLOCK 20
/* Verbose output from test if you set this to 1 */
#define MULTI_DIAG 0
static dbCommon **precords;
typedef struct {
@@ -120,6 +123,9 @@ void doMulti(workerPriv *p)
}
dbScanUnlockMany(locker);
if (MULTI_DIAG)
testDiag("sum = %d", sum);
dbLockerFree(locker);
}

View File

@@ -35,7 +35,6 @@ void z_open(struct link *plink)
if(priv->isopen)
testDiag("lsetZ re-open");
priv->isopen = 1;
testDiag("Open jlinkz %p", priv);
}
static
@@ -50,8 +49,6 @@ void z_remove(struct dbLocker *locker, struct link *plink)
epicsMutexUnlock(priv->lock);
testDiag("Remove/free jlinkz %p", priv);
epicsAtomicDecrIntT(&numzalloc);
epicsMutexDestroy(priv->lock);
@@ -83,13 +80,13 @@ long z_getval(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
long ret;
long (*pconv)(const epicsInt32 *, void *, const dbAddr *) = dbFastGetConvertRoutine[DBF_LONG][dbrType];
FASTCONVERTFUNC pconv = dbFastGetConvertRoutine[DBF_LONG][dbrType];
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
if(pnRequest && *pnRequest==0) return 0;
epicsMutexLock(priv->lock);
ret = (*pconv)(&priv->value, pbuffer, NULL);
ret = pconv(&priv->value, pbuffer, NULL);
epicsMutexUnlock(priv->lock);
if(ret==0 && pnRequest) *pnRequest = 1;
return ret;
@@ -118,19 +115,20 @@ long z_putval(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
long ret;
long (*pconv)(epicsInt32 *, const void *, const dbAddr *);
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
FASTCONVERTFUNC pconv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;
pconv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
pconv = dbFastPutConvertRoutine[dbrType][DBF_LONG];
if(nRequest==0) return 0;
epicsMutexLock(priv->lock);
ret = (*pconv)(&priv->value, pbuffer, NULL);
ret = pconv(pbuffer, &priv->value, NULL);
epicsMutexUnlock(priv->lock);
plink->precord->phas = priv->value;
return ret;
}
@@ -168,8 +166,6 @@ jlink* z_alloc(short dbfType)
epicsAtomicIncrIntT(&numzalloc);
testDiag("Alloc jlinkz %p", priv);
return &priv->base;
fail:
if(priv && priv->lock) epicsMutexDestroy(priv->lock);
@@ -185,8 +181,6 @@ void z_free(jlink *pj)
if(priv->isopen)
testDiag("lsetZ jlink free after open()");
testDiag("Free jlinkz %p", priv);
epicsAtomicDecrIntT(&numzalloc);
epicsMutexDestroy(priv->lock);

View File

@@ -71,6 +71,7 @@ static long process(struct dbCommon *pcommon)
ret = (*xset->process)(prec);
monitor(prec);
recGblGetTimeStamp(prec);
dbPutLink(&prec->outp, DBR_LONG, &prec->val, 1);
recGblFwdLink(prec);
prec->pact = FALSE;
return ret;

View File

@@ -49,6 +49,9 @@ recordtype(x) {
prompt("Input Link")
special(SPC_MOD)
}
field(OUTP, DBF_OUTLINK) {
prompt("Output Link")
}
field(CLBK, DBF_NOACCESS) {
prompt("Processing callback")
special(SPC_NOMOD)

View File

@@ -469,6 +469,38 @@ testNto1Average(void) {
testdbCleanup();
}
void testNto2Average(void) {
DBADDR wfaddr, caddr;
testDiag("Test N to 1 Average, NSAM=2, N=2");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=2");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
checkArrD("comp", 2, 1.5, 3.5, 0, 0);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1AveragePartial(void) {
double buf = 0.0;
@@ -517,6 +549,36 @@ testNto1AveragePartial(void) {
testdbCleanup();
}
void
testNtoMPartial(void) {
DBADDR wfaddr, caddr;
testDiag("Test Average, N to M, Partial");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=3,PBUF=YES");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
checkArrD("comp", 2, 2.0, 4.0, 0, 0);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1LowValue(void) {
double buf = 0.0;
@@ -634,12 +696,14 @@ testAIAveragePartial(void) {
MAIN(compressTest)
{
testPlan(132);
testPlan(134);
testFIFOCirc();
testLIFOCirc();
testArrayAverage();
testNto1Average();
testNto2Average();
testNto1AveragePartial();
testNtoMPartial();
testAIAveragePartial();
testNto1LowValue();
return testDone();

View File

@@ -522,7 +522,7 @@ void errPrintf(long status, const char *pFileName, int lineno,
errSymLookup(status, name, sizeof(name));
}
nchar = epicsSnprintf(buf, pvt.maxMsgSize, "%s%sfilename=\"%s\" line number=%d",
nchar = epicsSnprintf(buf, pvt.maxMsgSize, "%s%sfilename=\"%s\" line number=%d ",
name, status ? " " : "", pFileName, lineno);
if(nchar < pvt.maxMsgSize)
nchar += epicsVsnprintf(buf + nchar, pvt.maxMsgSize - nchar, pformat, pvar);

View File

@@ -1437,13 +1437,16 @@ static void varCallFunc(const iocshArgBuf *args)
varHandler(v->pVarDef, NULL);
found = 1;
}
if (!found && name != NULL)
if (!found && name != NULL) {
fprintf(epicsGetStderr(), ANSI_RED("No var matching") " %s found.\n", name);
iocshSetError(1);
}
}
else {
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
if (v == NULL) {
fprintf(epicsGetStderr(), "Var %s " ANSI_RED("not found.") "\n", name);
iocshSetError(1);
}
else {
varHandler(v->pVarDef, value);
@@ -1460,7 +1463,7 @@ static const iocshFuncDef iocshCmdFuncDef = {"iocshCmd",1,iocshCmdArgs,
" from vxWorks or RTEMS startup script (or command line)\n"};
static void iocshCmdCallFunc(const iocshArgBuf *args)
{
iocshCmd(args[0].sval);
iocshSetError(iocshCmd(args[0].sval));
}
/* iocshLoad */
@@ -1472,7 +1475,7 @@ static const iocshFuncDef iocshLoadFuncDef = {"iocshLoad",2,iocshLoadArgs,
" * (optional) replace macros within the file with provided values\n"};
static void iocshLoadCallFunc(const iocshArgBuf *args)
{
iocshLoad(args[0].sval, args[1].sval);
iocshSetError(iocshLoad(args[0].sval, args[1].sval));
}
/* iocshRun */
@@ -1485,7 +1488,7 @@ static const iocshFuncDef iocshRunFuncDef = {"iocshRun",2,iocshRunArgs,
" from vxWorks or RTEMS startup script (or command line)\n"};
static void iocshRunCallFunc(const iocshArgBuf *args)
{
iocshRun(args[0].sval, args[1].sval);
iocshSetError(iocshRun(args[0].sval, args[1].sval));
}
/* on */

View File

@@ -109,7 +109,7 @@ osdReadline (const char *prompt, struct readlineContext *context)
line[linelen] = '\0';
}
context->line = line;
if (line && *line)
if (line && *line && !context->in)
add_history(line);
return line;
}

View File

@@ -194,8 +194,8 @@ static void NTPTimeSync(void *dummy)
&NTPTimePvt.syncTime);
epicsTimeToStrftime(nowTimeText,sizeof(nowTimeText),"%Y-%m-%d %H:%M:%S.%09f",
&timeNow);
errlogPrintf("NTPTimeSync: refuse to jump from %s to future %s (timespec: %li.%09li)\n",
syncTimeText, nowTimeText, timespecNow.tv_sec, timespecNow.tv_nsec);
errlogPrintf("NTPTimeSync: refuse to jump from %s to future %s (timespec: %lli.%09li)\n",
syncTimeText, nowTimeText, (long long int)timespecNow.tv_sec, timespecNow.tv_nsec);
NTPTimePvt.synchronized = 0;
continue;
}