Merge branch 'libcom/master' back
This commit is contained in:
21
modules/libcom/.ci/travis-build.sh
Executable file
21
modules/libcom/.ci/travis-build.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
# find local qemu-system-i386
|
||||
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
|
||||
echo -n "Using QEMU: "
|
||||
type qemu-system-i386 || echo "Missing qemu"
|
||||
EXTRA=RTEMS_QEMU_FIXUPS=YES
|
||||
fi
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make -j2 tapfiles
|
||||
make -s test-results
|
||||
fi
|
||||
123
modules/libcom/.ci/travis-prepare.sh
Executable file
123
modules/libcom/.ci/travis-prepare.sh
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
CURDIR="$PWD"
|
||||
|
||||
QDIR="$HOME/.cache/qemu"
|
||||
|
||||
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
|
||||
then
|
||||
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
|
||||
cd "$HOME/.build/qemu"
|
||||
|
||||
HEAD=`git log -n1 --pretty=format:%H`
|
||||
echo "HEAD revision $HEAD"
|
||||
|
||||
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
|
||||
echo "Cached revision $BUILT"
|
||||
|
||||
if [ "$HEAD" != "$BUILT" ]
|
||||
then
|
||||
echo "Building QEMU"
|
||||
git submodule --quiet update --init
|
||||
|
||||
install -d "$HOME/.build/qemu/build"
|
||||
cd "$HOME/.build/qemu/build"
|
||||
|
||||
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
|
||||
make -j2
|
||||
make install
|
||||
|
||||
echo "$HEAD" > "$HOME/.cache/qemu/built"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$CURDIR"
|
||||
|
||||
cat << EOF > configure/RELEASE.local
|
||||
EPICS_BASE=$HOME/.source/epics-base
|
||||
EOF
|
||||
|
||||
install -d "$HOME/.source"
|
||||
cd "$HOME/.source"
|
||||
|
||||
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
|
||||
(cd epics-base && git log -n1 )
|
||||
|
||||
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
|
||||
|
||||
# requires wine and g++-mingw-w64-i686
|
||||
if [ "$WINE" = "32" ]
|
||||
then
|
||||
echo "Cross mingw32"
|
||||
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
CMPLR_PREFIX=i686-w64-mingw32-
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$STATIC" = "YES" ]
|
||||
then
|
||||
echo "Build static libraries/executables"
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
SHARED_LIBRARIES=NO
|
||||
STATIC_BUILD=YES
|
||||
EOF
|
||||
fi
|
||||
|
||||
case "$CMPLR" in
|
||||
clang)
|
||||
echo "Host compiler is clang"
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
EOF
|
||||
|
||||
# hack
|
||||
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
|
||||
|
||||
clang --version
|
||||
;;
|
||||
*)
|
||||
echo "Host compiler is default"
|
||||
gcc --version
|
||||
;;
|
||||
esac
|
||||
|
||||
cat <<EOF >> epics-base/configure/CONFIG_SITE
|
||||
USR_CPPFLAGS += $USR_CPPFLAGS
|
||||
USR_CFLAGS += $USR_CFLAGS
|
||||
USR_CXXFLAGS += $USR_CXXFLAGS
|
||||
EOF
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
echo "Cross RTEMS${RTEMS} for pc386"
|
||||
install -d /home/travis/.cache
|
||||
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
|
||||
| tar -C /home/travis/.cache -xj
|
||||
|
||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
RTEMS_VERSION=$RTEMS
|
||||
RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
|
||||
EOF
|
||||
|
||||
# find local qemu-system-i386
|
||||
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
|
||||
echo -n "Using QEMU: "
|
||||
type qemu-system-i386 || echo "Missing qemu"
|
||||
EXTRA=RTEMS_QEMU_FIXUPS=YES
|
||||
fi
|
||||
|
||||
make -j2 -C epics-base $EXTRA
|
||||
26
modules/libcom/.travis.yml
Normal file
26
modules/libcom/.travis.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
- clang
|
||||
- g++-mingw-w64-i686
|
||||
install:
|
||||
- ./.ci/travis-prepare.sh
|
||||
script:
|
||||
- ./.ci/travis-build.sh
|
||||
env:
|
||||
- BRCORE=master
|
||||
- CMPLR=clang
|
||||
- USR_CXXFLAGS=-std=c++11
|
||||
- CMPLR=clang USR_CXXFLAGS=-std=c++11
|
||||
- WINE=32 TEST=NO STATIC=YES
|
||||
- WINE=32 TEST=NO STATIC=NO
|
||||
- RTEMS=4.10 TEST=NO
|
||||
- RTEMS=4.9 TEST=NO
|
||||
25
modules/libcom/Makefile
Normal file
25
modules/libcom/Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP = .
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
DIRS += configure src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += RTEMS
|
||||
RTEMS_DEPEND_DIRS = src
|
||||
|
||||
DIRS += vxWorks
|
||||
vxWorks_DEPEND_DIRS = src
|
||||
|
||||
DIRS += test
|
||||
test_DEPEND_DIRS = RTEMS vxWorks
|
||||
|
||||
include $(TOP)/configure/RULES_TOP
|
||||
29
modules/libcom/RTEMS/Makefile
Normal file
29
modules/libcom/RTEMS/Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
include $(TOP)/configure/CONFIG_LIBCOM_VERSION
|
||||
|
||||
INC += epicsRtemsInitHooks.h
|
||||
|
||||
rtemsCom_SRCS += rtems_init.c
|
||||
rtemsCom_SRCS += rtems_config.c
|
||||
rtemsCom_SRCS += rtems_netconfig.c
|
||||
rtemsCom_SRCS += rtems_util.c
|
||||
rtemsCom_SRCS += setBootConfigFromNVRAM.c
|
||||
rtemsCom_SRCS += epicsRtemsInitHookPre.c
|
||||
rtemsCom_SRCS += epicsRtemsInitHookPost.c
|
||||
|
||||
LIBRARY_RTEMS = rtemsCom
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION = $(EPICS_LIBCOM_MAJOR_VERSION).$(EPICS_LIBCOM_MINOR_VERSION).$(EPICS_LIBCOM_MAINTENANCE_VERSION)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
18
modules/libcom/RTEMS/epicsRtemsInitHookPost.c
Normal file
18
modules/libcom/RTEMS/epicsRtemsInitHookPost.c
Normal file
@@ -0,0 +1,18 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Dummy version -- use if application does not provide its own version
|
||||
*/
|
||||
#include "epicsRtemsInitHooks.h"
|
||||
|
||||
int
|
||||
epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
18
modules/libcom/RTEMS/epicsRtemsInitHookPre.c
Normal file
18
modules/libcom/RTEMS/epicsRtemsInitHookPre.c
Normal file
@@ -0,0 +1,18 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Dummy version -- use if application does not provide its own version
|
||||
*/
|
||||
#include "epicsRtemsInitHooks.h"
|
||||
|
||||
int
|
||||
epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
23
modules/libcom/RTEMS/epicsRtemsInitHooks.h
Normal file
23
modules/libcom/RTEMS/epicsRtemsInitHooks.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Hooks into RTEMS startup code
|
||||
*/
|
||||
#include <bsp.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
|
||||
extern char *env_nfsServer;
|
||||
extern char *env_nfsPath;
|
||||
extern char *env_nfsMountPoint;
|
||||
|
||||
/*
|
||||
* Return 0 for success, non-zero for failure (will cause panic)
|
||||
*/
|
||||
int epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
|
||||
int epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
|
||||
71
modules/libcom/RTEMS/rtems_config.c
Normal file
71
modules/libcom/RTEMS/rtems_config.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS configuration for EPICS
|
||||
* Author: W. Eric Norum
|
||||
* norume@aps.anl.gov
|
||||
* (630) 252-4793
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* RTEMS CONFIGURATION *
|
||||
***********************************************************************
|
||||
*/
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
|
||||
# define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
#else
|
||||
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
|
||||
#endif
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
|
||||
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
|
||||
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
|
||||
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
|
||||
|
||||
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
|
||||
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
|
||||
#define CONFIGURE_MAXIMUM_DRIVERS 8
|
||||
|
||||
#define CONFIGURE_MICROSECONDS_PER_TICK 20000
|
||||
|
||||
#define CONFIGURE_INIT_TASK_PRIORITY 80
|
||||
|
||||
#define CONFIGURE_MALLOC_STATISTICS 1
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
|
||||
RTEMS_NO_TIMESLICE | \
|
||||
RTEMS_NO_ASR | \
|
||||
RTEMS_INTERRUPT_LEVEL(0))
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_FLOATING_POINT | RTEMS_LOCAL)
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE (16*1024)
|
||||
rtems_task Init (rtems_task_argument argument);
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_NFS
|
||||
#define CONFIGURE_FILESYSTEM_IMFS
|
||||
|
||||
/*
|
||||
* This should be made BSP dependent, not CPU dependent but I know of no
|
||||
* appropriate conditionals to use.
|
||||
* The new general time support makes including the RTC driverr less important.
|
||||
*/
|
||||
#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && !defined(mpc7455) && !defined(__arm__) && !defined(__nios2__)/* don't have RTC code */
|
||||
#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
|
||||
#endif
|
||||
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/confdefs.h>
|
||||
668
modules/libcom/RTEMS/rtems_init.c
Normal file
668
modules/libcom/RTEMS/rtems_init.c
Normal file
@@ -0,0 +1,668 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS startup task for EPICS
|
||||
* Author: W. Eric Norum
|
||||
* eric.norum@usask.ca
|
||||
* (306) 966-5394
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <rtems.h>
|
||||
#include <rtems/malloc.h>
|
||||
#include <rtems/error.h>
|
||||
#include <rtems/stackchk.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <rtems/imfs.h>
|
||||
#include <librtemsNfs.h>
|
||||
#include <bsp.h>
|
||||
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsExit.h"
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "logClient.h"
|
||||
#include "osiUnistd.h"
|
||||
#include "iocsh.h"
|
||||
#include "osdTime.h"
|
||||
|
||||
#include "epicsRtemsInitHooks.h"
|
||||
|
||||
/*
|
||||
* Prototypes for some functions not in header files
|
||||
*/
|
||||
void tzset(void);
|
||||
int fileno(FILE *);
|
||||
int main(int argc, char **argv);
|
||||
|
||||
static void
|
||||
logReset (void)
|
||||
{
|
||||
void rtems_bsp_reset_cause(char *buf, size_t capacity) __attribute__((weak));
|
||||
void (*fp)(char *buf, size_t capacity) = rtems_bsp_reset_cause;
|
||||
|
||||
if (fp) {
|
||||
char buf[80];
|
||||
fp(buf, sizeof buf);
|
||||
errlogPrintf ("Startup after %s.\n", buf);
|
||||
}
|
||||
else {
|
||||
errlogPrintf ("Startup.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* FATAL ERROR REPORTING *
|
||||
***********************************************************************
|
||||
*/
|
||||
/*
|
||||
* Delay for a while, then terminate
|
||||
*/
|
||||
static void
|
||||
delayedPanic (const char *msg)
|
||||
{
|
||||
extern rtems_interval rtemsTicksPerSecond;
|
||||
|
||||
rtems_task_wake_after (rtemsTicksPerSecond);
|
||||
rtems_panic (msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log error and terminate
|
||||
*/
|
||||
void
|
||||
LogFatal (const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, msg);
|
||||
errlogVprintf (msg, ap);
|
||||
va_end (ap);
|
||||
delayedPanic (msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log RTEMS error and terminate
|
||||
*/
|
||||
void
|
||||
LogRtemsFatal (const char *msg, rtems_status_code sc)
|
||||
{
|
||||
errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc));
|
||||
delayedPanic (msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Log network error and terminate
|
||||
*/
|
||||
void
|
||||
LogNetFatal (const char *msg, int err)
|
||||
{
|
||||
errlogPrintf ("%s: %d\n", msg, err);
|
||||
delayedPanic (msg);
|
||||
}
|
||||
|
||||
void *
|
||||
mustMalloc(int size, const char *msg)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = malloc (size)) == NULL)
|
||||
LogFatal ("Can't allocate space for %s.\n", msg);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* REMOTE FILE ACCESS *
|
||||
***********************************************************************
|
||||
*/
|
||||
#ifdef OMIT_NFS_SUPPORT
|
||||
# include <rtems/tftp.h>
|
||||
#endif
|
||||
|
||||
static int
|
||||
initialize_local_filesystem(char **argv)
|
||||
{
|
||||
extern char _DownloadLocation[] __attribute__((weak));
|
||||
extern char _FlashBase[] __attribute__((weak));
|
||||
extern char _FlashSize[] __attribute__((weak));
|
||||
|
||||
argv[0] = rtems_bsdnet_bootp_boot_file_name;
|
||||
if (_FlashSize && (_DownloadLocation || _FlashBase)) {
|
||||
extern char _edata[];
|
||||
size_t flashIndex = _edata - _DownloadLocation;
|
||||
char *header = _FlashBase + flashIndex;
|
||||
|
||||
if (memcmp(header + 257, "ustar ", 8) == 0) {
|
||||
int fd;
|
||||
printf ("***** Unpack in-memory file system (IMFS) *****\n");
|
||||
if (rtems_tarfs_load("/", (unsigned char *)header, (size_t)_FlashSize - flashIndex) != 0) {
|
||||
printf("Can't unpack tar filesystem\n");
|
||||
return 0;
|
||||
}
|
||||
if ((fd = open(rtems_bsdnet_bootp_cmdline, 0)) >= 0) {
|
||||
close(fd);
|
||||
printf ("***** Found startup script (%s) in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
|
||||
argv[1] = rtems_bsdnet_bootp_cmdline;
|
||||
return 1;
|
||||
}
|
||||
printf ("***** Startup script (%s) not in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef OMIT_NFS_SUPPORT
|
||||
#if __RTEMS_MAJOR__>4 || \
|
||||
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || \
|
||||
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
|
||||
int
|
||||
nfsMount(char *uidhost, char *path, char *mntpoint)
|
||||
{
|
||||
int devl = strlen(uidhost) + strlen(path) + 2;
|
||||
char *dev;
|
||||
int rval = -1;
|
||||
|
||||
if ((dev = malloc(devl)) == NULL) {
|
||||
fprintf(stderr,"nfsMount: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(dev, "%s:%s", uidhost, path);
|
||||
printf("Mount %s on %s\n", dev, mntpoint);
|
||||
if (rtems_mkdir(mntpoint, S_IRWXU | S_IRWXG | S_IRWXO))
|
||||
printf("Warning -- unable to make directory \"%s\"\n", mntpoint);
|
||||
if (mount(dev, mntpoint, RTEMS_FILESYSTEM_TYPE_NFS,
|
||||
RTEMS_FILESYSTEM_READ_WRITE, NULL)) {
|
||||
perror("mount failed");
|
||||
}
|
||||
else {
|
||||
rval = 0;
|
||||
}
|
||||
free(dev);
|
||||
return rval;
|
||||
}
|
||||
#define NFS_INIT
|
||||
#else
|
||||
#define NFS_INIT rpcUdpInit(); nfsInit(0,0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void
|
||||
initialize_remote_filesystem(char **argv, int hasLocalFilesystem)
|
||||
{
|
||||
#ifdef OMIT_NFS_SUPPORT
|
||||
printf ("***** Initializing TFTP *****\n");
|
||||
#if __RTEMS_MAJOR__>4 || \
|
||||
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || \
|
||||
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
|
||||
mount_and_make_target_path(NULL,
|
||||
"/TFTP",
|
||||
RTEMS_FILESYSTEM_TYPE_TFTPFS,
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
NULL);
|
||||
#else
|
||||
rtems_bsdnet_initialize_tftp_filesystem ();
|
||||
#endif
|
||||
if (!hasLocalFilesystem) {
|
||||
char *path;
|
||||
int pathsize = 200;
|
||||
int l;
|
||||
|
||||
path = mustMalloc(pathsize, "Command path name ");
|
||||
strcpy (path, "/TFTP/BOOTP_HOST/epics/");
|
||||
l = strlen (path);
|
||||
if (gethostname (&path[l], pathsize - l - 10) || (path[l] == '\0'))
|
||||
{
|
||||
LogFatal ("Can't get host name");
|
||||
}
|
||||
strcat (path, "/st.cmd");
|
||||
argv[1] = path;
|
||||
}
|
||||
#else
|
||||
char *server_name;
|
||||
char *server_path;
|
||||
char *mount_point;
|
||||
char *cp;
|
||||
int l = 0;
|
||||
|
||||
printf ("***** Initializing NFS *****\n");
|
||||
NFS_INIT
|
||||
if (env_nfsServer && env_nfsPath && env_nfsMountPoint) {
|
||||
server_name = env_nfsServer;
|
||||
server_path = env_nfsPath;
|
||||
mount_point = env_nfsMountPoint;
|
||||
cp = mount_point;
|
||||
while ((cp = strchr(cp+1, '/')) != NULL) {
|
||||
*cp = '\0';
|
||||
if ((mkdir (mount_point, 0755) != 0)
|
||||
&& (errno != EEXIST))
|
||||
LogFatal("Can't create directory \"%s\": %s.\n",
|
||||
mount_point, strerror(errno));
|
||||
*cp = '/';
|
||||
}
|
||||
argv[1] = rtems_bsdnet_bootp_cmdline;
|
||||
}
|
||||
else if (hasLocalFilesystem) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Use first component of nvram/bootp command line pathname
|
||||
* to set up initial NFS mount. A "/tftpboot/" is prepended
|
||||
* if the pathname does not begin with a '/'. This allows
|
||||
* NFS and TFTP to have a similar view of the remote system.
|
||||
*/
|
||||
if (rtems_bsdnet_bootp_cmdline[0] == '/')
|
||||
cp = rtems_bsdnet_bootp_cmdline + 1;
|
||||
else
|
||||
cp = rtems_bsdnet_bootp_cmdline;
|
||||
cp = strchr(cp, '/');
|
||||
if ((cp == NULL)
|
||||
|| ((l = cp - rtems_bsdnet_bootp_cmdline) == 0))
|
||||
LogFatal("\"%s\" is not a valid command pathname.\n", rtems_bsdnet_bootp_cmdline);
|
||||
cp = mustMalloc(l + 20, "NFS mount paths");
|
||||
server_path = cp;
|
||||
server_name = rtems_bsdnet_bootp_server_name;
|
||||
if (rtems_bsdnet_bootp_cmdline[0] == '/') {
|
||||
mount_point = server_path;
|
||||
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
|
||||
mount_point[l] = '\0';
|
||||
argv[1] = rtems_bsdnet_bootp_cmdline;
|
||||
/*
|
||||
* Its probably common to embed the mount point in the server
|
||||
* name so, when this is occurring, dont clobber the mount point
|
||||
* by appending the first node from the command path. This allows
|
||||
* the mount point to be a different path then the server's mount
|
||||
* path.
|
||||
*
|
||||
* This allows for example a line similar to as follows the DHCP
|
||||
* configuration file.
|
||||
*
|
||||
* server-name "159.233@192.168.0.123:/vol/vol0/bootRTEMS";
|
||||
*/
|
||||
if ( server_name ) {
|
||||
const size_t allocSize = strlen ( server_name ) + 2;
|
||||
char * const pServerName = mustMalloc( allocSize,
|
||||
"NFS mount paths");
|
||||
char * const pServerPath = mustMalloc ( allocSize,
|
||||
"NFS mount paths");
|
||||
const int scanfStatus = sscanf (
|
||||
server_name,
|
||||
"%[^:] : / %s",
|
||||
pServerName,
|
||||
pServerPath + 1u );
|
||||
if ( scanfStatus == 2 ) {
|
||||
pServerPath[0u]= '/';
|
||||
server_name = pServerName;
|
||||
server_path = pServerPath;
|
||||
}
|
||||
else {
|
||||
free ( pServerName );
|
||||
free ( pServerPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *abspath = mustMalloc(strlen(rtems_bsdnet_bootp_cmdline)+2,"Absolute command path");
|
||||
strcpy(server_path, "/tftpboot/");
|
||||
mount_point = server_path + strlen(server_path);
|
||||
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
|
||||
mount_point[l] = '\0';
|
||||
mount_point--;
|
||||
strcpy(abspath, "/");
|
||||
strcat(abspath, rtems_bsdnet_bootp_cmdline);
|
||||
argv[1] = abspath;
|
||||
}
|
||||
}
|
||||
errlogPrintf("nfsMount(\"%s\", \"%s\", \"%s\")\n",
|
||||
server_name, server_path, mount_point);
|
||||
nfsMount(server_name, server_path, mount_point);
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
char rtems_etc_hosts[] = "127.0.0.1 localhost\n";
|
||||
|
||||
/* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */
|
||||
static
|
||||
void fixup_hosts(void)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret;
|
||||
struct stat STAT;
|
||||
|
||||
ret=stat("/etc/hosts", &STAT);
|
||||
if(ret==0)
|
||||
{
|
||||
return; /* already exists, assume file */
|
||||
} else if(errno!=ENOENT) {
|
||||
perror("error: fixup_hosts stat /etc/hosts");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = mkdir("/etc", 0775);
|
||||
if(ret!=0 && errno!=EEXIST)
|
||||
{
|
||||
perror("error: fixup_hosts create /etc");
|
||||
return;
|
||||
}
|
||||
|
||||
if((fp=fopen("/etc/hosts", "w"))==NULL)
|
||||
{
|
||||
perror("error: fixup_hosts create /etc/hosts");
|
||||
}
|
||||
|
||||
if(fwrite(rtems_etc_hosts, 1, sizeof(rtems_etc_hosts)-1, fp)!=sizeof(rtems_etc_hosts)-1)
|
||||
{
|
||||
perror("error: failed to write /etc/hosts");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get to the startup script directory
|
||||
* The TFTP filesystem requires a trailing '/' on chdir arguments.
|
||||
*/
|
||||
static void
|
||||
set_directory (const char *commandline)
|
||||
{
|
||||
const char *cp;
|
||||
char *directoryPath;
|
||||
int l;
|
||||
|
||||
cp = strrchr(commandline, '/');
|
||||
if (cp == NULL) {
|
||||
l = 0;
|
||||
cp = "/";
|
||||
}
|
||||
else {
|
||||
l = cp - commandline;
|
||||
cp = commandline;
|
||||
}
|
||||
directoryPath = mustMalloc(l + 2, "Command path directory ");
|
||||
strncpy(directoryPath, cp, l);
|
||||
directoryPath[l] = '/';
|
||||
directoryPath[l+1] = '\0';
|
||||
if (chdir (directoryPath) < 0)
|
||||
LogFatal ("Can't set initial directory(%s): %s\n", directoryPath, strerror(errno));
|
||||
else
|
||||
errlogPrintf("chdir(\"%s\")\n", directoryPath);
|
||||
free(directoryPath);
|
||||
}
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* RTEMS/EPICS COMMANDS *
|
||||
***********************************************************************
|
||||
*/
|
||||
/*
|
||||
* RTEMS status
|
||||
*/
|
||||
static void
|
||||
rtems_netstat (unsigned int level)
|
||||
{
|
||||
rtems_bsdnet_show_if_stats ();
|
||||
rtems_bsdnet_show_mbuf_stats ();
|
||||
if (level >= 1) {
|
||||
rtems_bsdnet_show_inet_routes ();
|
||||
}
|
||||
if (level >= 2) {
|
||||
rtems_bsdnet_show_ip_stats ();
|
||||
rtems_bsdnet_show_icmp_stats ();
|
||||
rtems_bsdnet_show_udp_stats ();
|
||||
rtems_bsdnet_show_tcp_stats ();
|
||||
}
|
||||
}
|
||||
|
||||
static const iocshArg netStatArg0 = { "level",iocshArgInt};
|
||||
static const iocshArg * const netStatArgs[1] = {&netStatArg0};
|
||||
static const iocshFuncDef netStatFuncDef = {"netstat",1,netStatArgs};
|
||||
static void netStatCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
rtems_netstat(args[0].ival);
|
||||
}
|
||||
|
||||
static const iocshFuncDef heapSpaceFuncDef = {"heapSpace",0,NULL};
|
||||
static void heapSpaceCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
rtems_malloc_statistics_t s;
|
||||
double x;
|
||||
|
||||
malloc_get_statistics(&s);
|
||||
x = s.space_available - (unsigned long)(s.lifetime_allocated - s.lifetime_freed);
|
||||
if (x >= 1024*1024)
|
||||
printf("Heap space: %.1f MB\n", x / (1024 * 1024));
|
||||
else
|
||||
printf("Heap space: %.1f kB\n", x / 1024);
|
||||
}
|
||||
|
||||
#ifndef OMIT_NFS_SUPPORT
|
||||
static const iocshArg nfsMountArg0 = { "[uid.gid@]host",iocshArgString};
|
||||
static const iocshArg nfsMountArg1 = { "server path",iocshArgString};
|
||||
static const iocshArg nfsMountArg2 = { "mount point",iocshArgString};
|
||||
static const iocshArg * const nfsMountArgs[3] = {&nfsMountArg0,&nfsMountArg1,
|
||||
&nfsMountArg2};
|
||||
static const iocshFuncDef nfsMountFuncDef = {"nfsMount",3,nfsMountArgs};
|
||||
static void nfsMountCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
char *cp = args[2].sval;
|
||||
while ((cp = strchr(cp+1, '/')) != NULL) {
|
||||
*cp = '\0';
|
||||
if ((mkdir (args[2].sval, 0755) != 0) && (errno != EEXIST)) {
|
||||
printf("Can't create directory \"%s\": %s.\n",
|
||||
args[2].sval, strerror(errno));
|
||||
return;
|
||||
}
|
||||
*cp = '/';
|
||||
}
|
||||
nfsMount(args[0].sval, args[1].sval, args[2].sval);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register RTEMS-specific commands
|
||||
*/
|
||||
static void iocshRegisterRTEMS (void)
|
||||
{
|
||||
iocshRegister(&netStatFuncDef, netStatCallFunc);
|
||||
iocshRegister(&heapSpaceFuncDef, heapSpaceCallFunc);
|
||||
#ifndef OMIT_NFS_SUPPORT
|
||||
iocshRegister(&nfsMountFuncDef, nfsMountCallFunc);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the console serial line (no handshaking)
|
||||
*/
|
||||
static void
|
||||
initConsole (void)
|
||||
{
|
||||
struct termios t;
|
||||
|
||||
if (tcgetattr (fileno (stdin), &t) < 0) {
|
||||
printf ("tcgetattr failed: %s\n", strerror (errno));
|
||||
return;
|
||||
}
|
||||
t.c_iflag &= ~(IXOFF | IXON | IXANY);
|
||||
if (tcsetattr (fileno (stdin), TCSANOW, &t) < 0) {
|
||||
printf ("tcsetattr failed: %s\n", strerror (errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the configuration object files
|
||||
* get pulled in from the library
|
||||
*/
|
||||
extern rtems_configuration_table Configuration;
|
||||
extern struct rtems_bsdnet_config rtems_bsdnet_config;
|
||||
const void *rtemsConfigArray[] = {
|
||||
&Configuration,
|
||||
&rtems_bsdnet_config
|
||||
};
|
||||
|
||||
/*
|
||||
* Hook to ensure that BSP cleanup code gets run on exit
|
||||
*/
|
||||
static void
|
||||
exitHandler(void)
|
||||
{
|
||||
rtems_shutdown_executive(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTEMS Startup task
|
||||
*/
|
||||
rtems_task
|
||||
Init (rtems_task_argument ignored)
|
||||
{
|
||||
int result;
|
||||
char *argv[3] = { NULL, NULL, NULL };
|
||||
char *cp;
|
||||
rtems_task_priority newpri;
|
||||
rtems_status_code sc;
|
||||
rtems_time_of_day now;
|
||||
|
||||
/*
|
||||
* Explain why we're here
|
||||
*/
|
||||
logReset();
|
||||
|
||||
/*
|
||||
* Architecture-specific hooks
|
||||
*/
|
||||
if (epicsRtemsInitPreSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
|
||||
delayedPanic("epicsRtemsInitPreSetBootConfigFromNVRAM");
|
||||
if (rtems_bsdnet_config.bootp == NULL) {
|
||||
extern void setBootConfigFromNVRAM(void);
|
||||
setBootConfigFromNVRAM();
|
||||
}
|
||||
if (epicsRtemsInitPostSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
|
||||
delayedPanic("epicsRtemsInitPostSetBootConfigFromNVRAM");
|
||||
|
||||
/*
|
||||
* Override RTEMS configuration
|
||||
*/
|
||||
rtems_task_set_priority (
|
||||
RTEMS_SELF,
|
||||
epicsThreadGetOssPriorityValue(epicsThreadPriorityIocsh),
|
||||
&newpri);
|
||||
|
||||
/*
|
||||
* Create a reasonable environment
|
||||
*/
|
||||
initConsole ();
|
||||
putenv ("TERM=xterm");
|
||||
putenv ("IOCSH_HISTSIZE=20");
|
||||
|
||||
/*
|
||||
* Display some OS information
|
||||
*/
|
||||
printf("\n***** RTEMS Version: %s *****\n",
|
||||
rtems_get_version_string());
|
||||
|
||||
/*
|
||||
* Start network
|
||||
*/
|
||||
if ((cp = getenv("EPICS_TS_NTP_INET")) != NULL)
|
||||
rtems_bsdnet_config.ntp_server[0] = cp;
|
||||
if (rtems_bsdnet_config.network_task_priority == 0)
|
||||
{
|
||||
unsigned int p;
|
||||
if (epicsThreadHighestPriorityLevelBelow(epicsThreadPriorityScanLow, &p)
|
||||
== epicsThreadBooleanStatusSuccess)
|
||||
{
|
||||
rtems_bsdnet_config.network_task_priority = epicsThreadGetOssPriorityValue(p);
|
||||
}
|
||||
}
|
||||
printf("\n***** Initializing network *****\n");
|
||||
rtems_bsdnet_initialize_network();
|
||||
initialize_remote_filesystem(argv, initialize_local_filesystem(argv));
|
||||
fixup_hosts();
|
||||
|
||||
/*
|
||||
* More environment: iocsh prompt and hostname
|
||||
*/
|
||||
{
|
||||
char hostname[1024];
|
||||
gethostname(hostname, 1023);
|
||||
char *cp = mustMalloc(strlen(hostname)+3, "iocsh prompt");
|
||||
sprintf(cp, "%s> ", hostname);
|
||||
epicsEnvSet ("IOCSH_PS1", cp);
|
||||
epicsEnvSet("IOC_NAME", hostname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use BSP-supplied time of day if available otherwise supply default time.
|
||||
* It is very likely that other time synchronization facilities in EPICS
|
||||
* will soon override this value.
|
||||
*/
|
||||
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&now) != RTEMS_SUCCESSFUL) {
|
||||
now.year = 2001;
|
||||
now.month = 1;
|
||||
now.day = 1;
|
||||
now.hour = 0;
|
||||
now.minute = 0;
|
||||
now.second = 0;
|
||||
now.ticks = 0;
|
||||
if ((sc = rtems_clock_set (&now)) != RTEMS_SUCCESSFUL)
|
||||
printf ("***** Can't set time: %s\n", rtems_status_text (sc));
|
||||
}
|
||||
if (getenv("TZ") == NULL) {
|
||||
const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE);
|
||||
if (tzp == NULL) {
|
||||
printf("Warning -- no timezone information available -- times will be displayed as GMT.\n");
|
||||
}
|
||||
else {
|
||||
char tz[10];
|
||||
int minWest, toDst = 0, fromDst = 0;
|
||||
if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) {
|
||||
printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp);
|
||||
}
|
||||
else {
|
||||
char posixTzBuf[40];
|
||||
char *p = posixTzBuf;
|
||||
p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60);
|
||||
if (toDst != fromDst)
|
||||
p += sprintf(p, "%cDT", tz[0]);
|
||||
epicsEnvSet("TZ", posixTzBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
tzset();
|
||||
osdTimeRegister();
|
||||
|
||||
/*
|
||||
* Run the EPICS startup script
|
||||
*/
|
||||
printf ("***** Preparing EPICS application *****\n");
|
||||
iocshRegisterRTEMS ();
|
||||
set_directory (argv[1]);
|
||||
epicsEnvSet ("IOC_STARTUP_SCRIPT", argv[1]);
|
||||
atexit(exitHandler);
|
||||
errlogFlush();
|
||||
printf ("***** Starting EPICS application *****\n");
|
||||
result = main ((sizeof argv / sizeof argv[0]) - 1, argv);
|
||||
printf ("***** IOC application terminating *****\n");
|
||||
epicsThreadSleep(1.0);
|
||||
epicsExit(result);
|
||||
}
|
||||
120
modules/libcom/RTEMS/rtems_netconfig.c
Normal file
120
modules/libcom/RTEMS/rtems_netconfig.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS network configuration for EPICS
|
||||
* Author: W. Eric Norum
|
||||
* eric.norum@usask.ca
|
||||
* (306) 966-5394
|
||||
*
|
||||
* This file can be copied to an application source dirctory
|
||||
* and modified to override the values shown below.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <bsp.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
|
||||
extern void rtems_bsdnet_loopattach();
|
||||
static struct rtems_bsdnet_ifconfig loopback_config = {
|
||||
"lo0", /* name */
|
||||
(int (*)(struct rtems_bsdnet_ifconfig *, int))rtems_bsdnet_loopattach, /* attach function */
|
||||
NULL, /* link to next interface */
|
||||
"127.0.0.1", /* IP address */
|
||||
"255.0.0.0", /* IP net mask */
|
||||
};
|
||||
|
||||
/*
|
||||
* The following conditionals select the network interface card.
|
||||
*
|
||||
* On RTEMS-pc386 targets all network drivers which support run-time
|
||||
* probing are linked.
|
||||
* On other targets the network interface specified by the board-support
|
||||
* package is used.
|
||||
* To use a different NIC for a particular application, copy this file to the
|
||||
* application directory and make the appropriate changes.
|
||||
*/
|
||||
#if defined(__i386__)
|
||||
extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
static struct rtems_bsdnet_ifconfig fxp_driver_config = {
|
||||
"fxp1", /* name */
|
||||
rtems_fxp_attach, /* attach function */
|
||||
&loopback_config, /* link to next interface */
|
||||
};
|
||||
extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
|
||||
static struct rtems_bsdnet_ifconfig e3c509_driver_config = {
|
||||
"ep0", /* name */
|
||||
rtems_3c509_driver_attach, /* attach function */
|
||||
&fxp_driver_config, /* link to next interface */
|
||||
};
|
||||
#define FIRST_DRIVER_CONFIG &e3c509_driver_config
|
||||
#else
|
||||
|
||||
# if defined(__PPC)
|
||||
/*
|
||||
* FIXME: This really belongs in the BSP
|
||||
*/
|
||||
# ifndef RTEMS_BSP_NETWORK_DRIVER_NAME
|
||||
# define RTEMS_BSP_NETWORK_DRIVER_NAME "dc1"
|
||||
# endif
|
||||
# ifndef RTEMS_BSP_NETWORK_DRIVER_ATTACH
|
||||
# define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_dec21140_driver_attach
|
||||
extern int rtems_dec21140_driver_attach();
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static struct rtems_bsdnet_ifconfig bsp_driver_config = {
|
||||
RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
|
||||
RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
|
||||
&loopback_config, /* link to next interface */
|
||||
};
|
||||
#define FIRST_DRIVER_CONFIG &bsp_driver_config
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow configure/os/CONFIG_SITE.Common.RTEMS to provide domain name
|
||||
*/
|
||||
#ifdef RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME
|
||||
# define XSTR(x) STR(x)
|
||||
# define STR(x) #x
|
||||
# define MY_DOMAINNAME XSTR(RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME)
|
||||
#else
|
||||
# define MY_DOMAINNAME NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow non-BOOTP network configuration
|
||||
*/
|
||||
#ifndef MY_DO_BOOTP
|
||||
# define MY_DO_BOOTP rtems_bsdnet_do_bootp
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow site- and BSP-specific network buffer space configuration.
|
||||
* The macro values are specified in KBytes.
|
||||
*/
|
||||
#ifndef RTEMS_NETWORK_CONFIG_MBUF_SPACE
|
||||
# define RTEMS_NETWORK_CONFIG_MBUF_SPACE 180
|
||||
#endif
|
||||
#ifndef RTEMS_NETWORK_CONFIG_CLUSTER_SPACE
|
||||
# define RTEMS_NETWORK_CONFIG_CLUSTER_SPACE 350
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network configuration
|
||||
*/
|
||||
struct rtems_bsdnet_config rtems_bsdnet_config = {
|
||||
FIRST_DRIVER_CONFIG, /* Link to next interface */
|
||||
MY_DO_BOOTP, /* How to find network config */
|
||||
10, /* If 0 then the network daemons will run at a */
|
||||
/* priority just less than the lowest-priority */
|
||||
/* EPICS scan thread. */
|
||||
/* If non-zero then the network daemons will run */
|
||||
/* at this *RTEMS* priority */
|
||||
RTEMS_NETWORK_CONFIG_MBUF_SPACE*1024,
|
||||
RTEMS_NETWORK_CONFIG_CLUSTER_SPACE*1024,
|
||||
NULL, /* Host name */
|
||||
MY_DOMAINNAME, /* Domain name */
|
||||
};
|
||||
44
modules/libcom/RTEMS/rtems_util.c
Normal file
44
modules/libcom/RTEMS/rtems_util.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS utilitiy routines for EPICS
|
||||
* Author: W. Eric Norum
|
||||
* eric@cls.usask.ca
|
||||
* (306) 966-6055
|
||||
*
|
||||
* Supplies routines that are present in vxWorks but missing in RTEMS.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/*
|
||||
* Like connect(), but with an explicit timeout
|
||||
*/
|
||||
int connectWithTimeout (int sfd,
|
||||
struct sockaddr *addr,
|
||||
int addrlen,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
struct timeval sv;
|
||||
socklen_t svlen = sizeof sv;
|
||||
int ret;
|
||||
|
||||
if (!timeout)
|
||||
return connect (sfd, addr, addrlen);
|
||||
if (getsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&sv, &svlen) < 0)
|
||||
return -1;
|
||||
if (setsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)timeout, sizeof *timeout) < 0)
|
||||
return -1;
|
||||
ret = connect (sfd, addr, addrlen);
|
||||
setsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&sv, sizeof sv);
|
||||
return ret;
|
||||
}
|
||||
370
modules/libcom/RTEMS/setBootConfigFromNVRAM.c
Normal file
370
modules/libcom/RTEMS/setBootConfigFromNVRAM.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <bsp.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <epicsStdlib.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsString.h>
|
||||
#include <envDefs.h>
|
||||
|
||||
char *env_nfsServer;
|
||||
char *env_nfsPath;
|
||||
char *env_nfsMountPoint;
|
||||
|
||||
/*
|
||||
* Split argument string of form nfs_server:nfs_export:<path>
|
||||
* The nfs_export component will be used as:
|
||||
* - the path to the directory exported from the NFS server
|
||||
* - the local mount point
|
||||
* - a prefix of <path>
|
||||
* For example, the argument string:
|
||||
* romeo:/export/users:smith/ioc/iocexample/st.cmd
|
||||
* would:
|
||||
* - mount /export/users from NFS server romeo on /export/users
|
||||
* - chdir to /export/users/smith/ioc/iocexample
|
||||
* - read commands from st.cmd
|
||||
*/
|
||||
static void
|
||||
splitRtemsBsdnetBootpCmdline(void)
|
||||
{
|
||||
char *cp1, *cp2, *cp3;
|
||||
|
||||
if ((cp1 = rtems_bsdnet_bootp_cmdline) == NULL)
|
||||
return;
|
||||
if (((cp2 = strchr(cp1, ':')) != NULL)
|
||||
&& (((cp3 = strchr(cp2+1, ' ')) != NULL)
|
||||
|| ((cp3 = strchr(cp2+1, ':')) != NULL))) {
|
||||
int l1 = cp2 - cp1;
|
||||
int l2 = cp3 - cp2 - 1;
|
||||
int l3 = strlen(cp3) - 1;
|
||||
if (l1 && l2 && l3) {
|
||||
*cp2++ = '\0';
|
||||
*cp3 = '\0';
|
||||
env_nfsServer = cp1;
|
||||
env_nfsMountPoint = env_nfsPath = epicsStrDup(cp2);
|
||||
*cp3 = '/';
|
||||
rtems_bsdnet_bootp_cmdline = cp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Split NFS mount information of the form nfs_server:host_path:local_path
|
||||
*/
|
||||
static void
|
||||
splitNfsMountPath(char *nfsString)
|
||||
{
|
||||
char *cp2, *cp3;
|
||||
|
||||
if (nfsString == NULL)
|
||||
return;
|
||||
if (((cp2 = strchr(nfsString, ':')) != NULL)
|
||||
&& (((cp3 = strchr(cp2+1, ' ')) != NULL)
|
||||
|| ((cp3 = strchr(cp2+1, ':')) != NULL))) {
|
||||
int l1 = cp2 - nfsString;
|
||||
int l2 = cp3 - cp2 - 1;
|
||||
int l3 = strlen(cp3) - 1;
|
||||
if (l1 && l2 && l3) {
|
||||
*cp2++ = '\0';
|
||||
*cp3++ = '\0';
|
||||
env_nfsServer = nfsString;
|
||||
env_nfsPath = cp2;
|
||||
env_nfsMountPoint = cp3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_MOTLOAD)
|
||||
|
||||
/*
|
||||
* Motorola MOTLOAD NVRAM Access
|
||||
*/
|
||||
static char *
|
||||
gev(const char *parm, volatile char *nvp)
|
||||
{
|
||||
const char *val;
|
||||
const char *name;
|
||||
char *ret;
|
||||
char c;
|
||||
|
||||
for (;;) {
|
||||
if (*nvp == '\0')
|
||||
return NULL;
|
||||
name = parm;
|
||||
while ((c = *nvp++) != '\0') {
|
||||
if ((c == '=') && (*name == '\0')) {
|
||||
val = (char *)nvp;
|
||||
while (*nvp++ != '\0')
|
||||
continue;
|
||||
ret = malloc(nvp - val);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
strcpy(ret, val);
|
||||
return ret;
|
||||
}
|
||||
if (c != *name++) {
|
||||
while (*nvp++ != '\0')
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
motScriptParm(const char *mot_script_boot, char parm)
|
||||
{
|
||||
const char *cp;
|
||||
char *ret;
|
||||
int l;
|
||||
|
||||
while (*mot_script_boot != '\0') {
|
||||
if (isspace(*(unsigned char *)mot_script_boot)
|
||||
&& (*(mot_script_boot+1) == '-')
|
||||
&& (*(mot_script_boot+2) == parm)) {
|
||||
mot_script_boot += 3;
|
||||
cp = mot_script_boot;
|
||||
while ((*mot_script_boot != '\0') &&
|
||||
!isspace(*(unsigned char *)mot_script_boot))
|
||||
mot_script_boot++;
|
||||
l = mot_script_boot - cp;
|
||||
ret = malloc(l+1);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
strncpy(ret, cp, l);
|
||||
*(ret+l) = '\0';
|
||||
return ret;
|
||||
}
|
||||
mot_script_boot++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
setBootConfigFromNVRAM(void)
|
||||
{
|
||||
char *cp;
|
||||
const char *mot_script_boot;
|
||||
char *nvp;
|
||||
|
||||
# if defined(BSP_NVRAM_BASE_ADDR)
|
||||
nvp = (volatile unsigned char *)(BSP_NVRAM_BASE_ADDR+0x70f8);
|
||||
# elif defined(BSP_I2C_VPD_EEPROM_DEV_NAME)
|
||||
char gev_buf[3592];
|
||||
int fd;
|
||||
if ((fd = open(BSP_I2C_VPD_EEPROM_DEV_NAME, 0)) < 0) {
|
||||
printf("Can't open %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
|
||||
return;
|
||||
}
|
||||
lseek(fd, 0x10f8, SEEK_SET);
|
||||
if (read(fd, gev_buf, sizeof gev_buf) != sizeof gev_buf) {
|
||||
printf("Can't read %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
nvp = gev_buf;
|
||||
# else
|
||||
# error "No way to read GEV!"
|
||||
# endif
|
||||
|
||||
if (rtems_bsdnet_config.bootp != NULL)
|
||||
return;
|
||||
mot_script_boot = gev("mot-script-boot", nvp);
|
||||
if ((rtems_bsdnet_bootp_server_name = gev("mot-/dev/enet0-sipa", nvp)) == NULL)
|
||||
rtems_bsdnet_bootp_server_name = motScriptParm(mot_script_boot, 's');
|
||||
if ((rtems_bsdnet_config.gateway = gev("mot-/dev/enet0-gipa", nvp)) == NULL)
|
||||
rtems_bsdnet_config.gateway = motScriptParm(mot_script_boot, 'g');
|
||||
if ((rtems_bsdnet_config.ifconfig->ip_netmask = gev("mot-/dev/enet0-snma", nvp)) == NULL)
|
||||
rtems_bsdnet_config.ifconfig->ip_netmask = motScriptParm(mot_script_boot, 'm');
|
||||
|
||||
rtems_bsdnet_config.name_server[0] = gev("rtems-dns-server", nvp);
|
||||
if (rtems_bsdnet_config.name_server[0] == NULL)
|
||||
rtems_bsdnet_config.name_server[0] = rtems_bsdnet_bootp_server_name;
|
||||
cp = gev("rtems-dns-domainname", nvp);
|
||||
if (cp)
|
||||
rtems_bsdnet_config.domainname = cp;
|
||||
|
||||
if ((rtems_bsdnet_config.ifconfig->ip_address = gev("mot-/dev/enet0-cipa", nvp)) == NULL)
|
||||
rtems_bsdnet_config.ifconfig->ip_address = motScriptParm(mot_script_boot, 'c');
|
||||
rtems_bsdnet_config.hostname = gev("rtems-client-name", nvp);
|
||||
if (rtems_bsdnet_config.hostname == NULL)
|
||||
rtems_bsdnet_config.hostname = rtems_bsdnet_config.ifconfig->ip_address;
|
||||
|
||||
if ((rtems_bsdnet_bootp_boot_file_name = gev("mot-/dev/enet0-file", nvp)) == NULL)
|
||||
rtems_bsdnet_bootp_boot_file_name = motScriptParm(mot_script_boot, 'f');
|
||||
rtems_bsdnet_bootp_cmdline = gev("epics-script", nvp);
|
||||
splitRtemsBsdnetBootpCmdline();
|
||||
splitNfsMountPath(gev("epics-nfsmount", nvp));
|
||||
rtems_bsdnet_config.ntp_server[0] = gev("epics-ntpserver", nvp);
|
||||
if (rtems_bsdnet_config.ntp_server[0] == NULL)
|
||||
rtems_bsdnet_config.ntp_server[0] = rtems_bsdnet_bootp_server_name;
|
||||
if ((cp = gev("epics-tz", nvp)) != NULL)
|
||||
epicsEnvSet("TZ", cp);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PPCBUG)
|
||||
/*
|
||||
* Motorola PPCBUG NVRAM Access
|
||||
*/
|
||||
struct ppcbug_nvram {
|
||||
uint32_t PacketVersionIdentifier;
|
||||
uint32_t NodeControlMemoryAddress;
|
||||
uint32_t BootFileLoadAddress;
|
||||
uint32_t BootFileExecutionAddress;
|
||||
uint32_t BootFileExecutionDelay;
|
||||
uint32_t BootFileLength;
|
||||
uint32_t BootFileByteOffset;
|
||||
uint32_t TraceBufferAddress;
|
||||
uint32_t ClientIPAddress;
|
||||
uint32_t ServerIPAddress;
|
||||
uint32_t SubnetIPAddressMask;
|
||||
uint32_t BroadcastIPAddressMask;
|
||||
uint32_t GatewayIPAddress;
|
||||
uint8_t BootpRarpRetry;
|
||||
uint8_t TftpRarpRetry;
|
||||
uint8_t BootpRarpControl;
|
||||
uint8_t UpdateControl;
|
||||
char BootFilenameString[64];
|
||||
char ArgumentFilenameString[64];
|
||||
};
|
||||
|
||||
static char *addr(char *cbuf, uint32_t addr)
|
||||
{
|
||||
struct in_addr a;
|
||||
if ((a.s_addr = addr) == 0)
|
||||
return NULL;
|
||||
return (char *)inet_ntop(AF_INET, &a, cbuf, INET_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
void
|
||||
setBootConfigFromNVRAM(void)
|
||||
{
|
||||
static struct ppcbug_nvram nvram;
|
||||
static char ip_address[INET_ADDRSTRLEN];
|
||||
static char ip_netmask[INET_ADDRSTRLEN];
|
||||
static char server[INET_ADDRSTRLEN];
|
||||
static char gateway[INET_ADDRSTRLEN];
|
||||
|
||||
if (rtems_bsdnet_config.bootp != NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Get network configuation from PPCBUG.
|
||||
* The 'correct' way to do this would be to issue a .NETCFIG PPCBUG
|
||||
* system call. Unfortunately it is very difficult to issue such a
|
||||
* call once RTEMS is up and running so we just copy from the 'known'
|
||||
* location of the network configuration parameters.
|
||||
* Care must be taken to access the NVRAM a byte at a time.
|
||||
*/
|
||||
|
||||
#if defined(NVRAM_INDIRECT)
|
||||
{
|
||||
volatile char *addrLo = (volatile char *)0x80000074;
|
||||
volatile char *addrHi = (volatile char *)0x80000075;
|
||||
volatile char *data = (volatile char *)0x80000077;
|
||||
int addr = 0x1000;
|
||||
char *d = (char *)&nvram;
|
||||
|
||||
while (d < ((char *)&nvram + sizeof nvram)) {
|
||||
*addrLo = addr & 0xFF;
|
||||
*addrHi = (addr >> 8) & 0xFF;
|
||||
*d++ = *data;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
volatile char *s = (volatile char *)0xFFE81000;
|
||||
char *d = (char *)&nvram;
|
||||
|
||||
while (d < ((char *)&nvram + sizeof nvram))
|
||||
*d++ = *s++;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Assume that the boot server is also the name, log and ntp server!
|
||||
*/
|
||||
rtems_bsdnet_config.name_server[0] =
|
||||
rtems_bsdnet_config.ntp_server[0] =
|
||||
rtems_bsdnet_bootp_server_name = addr(server, nvram.ServerIPAddress);
|
||||
rtems_bsdnet_bootp_server_address.s_addr = nvram.ServerIPAddress;
|
||||
/*
|
||||
* Nothing better to use as host name!
|
||||
*/
|
||||
rtems_bsdnet_config.ifconfig->ip_address =
|
||||
rtems_bsdnet_config.hostname = addr(ip_address, nvram.ClientIPAddress);
|
||||
|
||||
rtems_bsdnet_config.gateway = addr(gateway, nvram.GatewayIPAddress);
|
||||
rtems_bsdnet_config.ifconfig->ip_netmask = addr(ip_netmask, nvram.SubnetIPAddressMask);
|
||||
|
||||
rtems_bsdnet_bootp_boot_file_name = nvram.BootFilenameString;
|
||||
rtems_bsdnet_bootp_cmdline = nvram.ArgumentFilenameString;
|
||||
splitRtemsBsdnetBootpCmdline();
|
||||
}
|
||||
|
||||
#elif defined(__mcf528x__)
|
||||
|
||||
static char *
|
||||
env(const char *parm, const char *defaultValue)
|
||||
{
|
||||
const char *cp = bsp_getbenv(parm);
|
||||
|
||||
if (!cp) {
|
||||
if (!defaultValue)
|
||||
return NULL;
|
||||
cp = defaultValue;
|
||||
printf ("%s environment variable missing -- using %s.\n", parm, cp);
|
||||
}
|
||||
return epicsStrDup(cp);
|
||||
}
|
||||
|
||||
void
|
||||
setBootConfigFromNVRAM(void)
|
||||
{
|
||||
const char *cp1;
|
||||
|
||||
if (rtems_bsdnet_config.bootp != NULL)
|
||||
return;
|
||||
rtems_bsdnet_config.gateway = env("GATEWAY", NULL);
|
||||
rtems_bsdnet_config.ifconfig->ip_netmask = env("NETMASK", "255.255.252.0");
|
||||
|
||||
rtems_bsdnet_bootp_server_name = env("SERVER", "192.168.0.1");
|
||||
rtems_bsdnet_config.name_server[0] = env("NAMESERVER", rtems_bsdnet_bootp_server_name);
|
||||
rtems_bsdnet_config.ntp_server[0] = env("NTPSERVER", rtems_bsdnet_bootp_server_name);
|
||||
cp1 = env("DOMAIN", NULL);
|
||||
if (cp1 != NULL)
|
||||
rtems_bsdnet_config.domainname = cp1;
|
||||
rtems_bsdnet_config.hostname = env("HOSTNAME", "iocNobody");
|
||||
rtems_bsdnet_config.ifconfig->ip_address = env("IPADDR0", "192.168.0.2");
|
||||
rtems_bsdnet_bootp_boot_file_name = env("BOOTFILE", "uC5282App.boot");
|
||||
rtems_bsdnet_bootp_cmdline = env("CMDLINE", "epics/iocBoot/iocNobody/st.cmd");
|
||||
splitNfsMountPath(env("NFSMOUNT", NULL));
|
||||
if ((cp1 = env("TZ", NULL)) != NULL)
|
||||
epicsEnvSet("TZ", cp1);
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* Placeholder for systems without NVRAM
|
||||
*/
|
||||
void
|
||||
setBootConfigFromNVRAM(void)
|
||||
{
|
||||
printf("SYSTEM HAS NO NON-VOLATILE RAM!\n");
|
||||
printf("YOU MUST USE SOME OTHER METHOD TO OBTAIN NETWORK CONFIGURATION\n");
|
||||
}
|
||||
#endif
|
||||
44
modules/libcom/configure/CONFIG
Normal file
44
modules/libcom/configure/CONFIG
Normal file
@@ -0,0 +1,44 @@
|
||||
# CONFIG - Load build configuration data
|
||||
#
|
||||
# Do not make changes to this file!
|
||||
|
||||
ifeq ($(strip $(EPICS_HOST_ARCH)),)
|
||||
$(warning EPICS_HOST_ARCH is not set.)
|
||||
endif
|
||||
|
||||
# Allow user to override where the build rules come from
|
||||
RULES = $(EPICS_BASE)
|
||||
|
||||
# RELEASE files point to other application tops
|
||||
include $(TOP)/configure/RELEASE
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
ifdef T_A
|
||||
-include $(TOP)/configure/RELEASE.Common.$(T_A)
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(RULES)),)
|
||||
ifeq ($(strip $(EPICS_BASE)),)
|
||||
$(warning Build error: EPICS_BASE not set after including RELEASE files.)
|
||||
else
|
||||
$(warning Build error: EPICS_BASE set but RULES variable empty.)
|
||||
endif
|
||||
$(error Makefiles loaded: $(MAKEFILE_LIST))
|
||||
# Die before the include of $(CONFIG)/CONFIG below does
|
||||
endif
|
||||
|
||||
BUILDING_LIBCOM = DEFINED
|
||||
|
||||
CONFIG = $(RULES)/configure
|
||||
include $(CONFIG)/CONFIG
|
||||
|
||||
# Override the Base definition:
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
|
||||
# CONFIG_SITE files contain other build configuration settings
|
||||
include $(TOP)/configure/CONFIG_SITE
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
ifdef T_A
|
||||
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
25
modules/libcom/configure/CONFIG_LIBCOM_MODULE
Normal file
25
modules/libcom/configure/CONFIG_LIBCOM_MODULE
Normal file
@@ -0,0 +1,25 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set EPICS_LIBCOM if necessary
|
||||
ifndef EPICS_LIBCOM
|
||||
EPICS_LIBCOM = $(if $(BUILDING_LIBCOM),$(INSTALL_LOCATION),$(EPICS_BASE))
|
||||
|
||||
# Paths to tools built here
|
||||
EPICS_LIBCOM_HOST_BIN ?= $(EPICS_LIBCOM)/bin/$(EPICS_HOST_ARCH)
|
||||
endif
|
||||
|
||||
# Set location of locally generated tools
|
||||
YACC = $(abspath $(EPICS_LIBCOM_HOST_BIN))/antelope$(HOSTEXE)
|
||||
LEX = $(abspath $(EPICS_LIBCOM_HOST_BIN))/e_flex$(HOSTEXE) \
|
||||
-S$(EPICS_LIBCOM)/include/flex.skel.static
|
||||
|
||||
# Default stack size for osiThread
|
||||
OSITHREAD_USE_DEFAULT_STACK = NO
|
||||
OSITHREAD_DEFAULT_STACK_FLAGS_YES = -DOSITHREAD_USE_DEFAULT_STACK
|
||||
|
||||
BASE_CPPFLAGS += $(OSITHREAD_DEFAULT_STACK_FLAGS_$(OSITHREAD_USE_DEFAULT_STACK))
|
||||
4
modules/libcom/configure/CONFIG_LIBCOM_VERSION
Normal file
4
modules/libcom/configure/CONFIG_LIBCOM_VERSION
Normal file
@@ -0,0 +1,4 @@
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 17
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
|
||||
42
modules/libcom/configure/CONFIG_SITE
Normal file
42
modules/libcom/configure/CONFIG_SITE
Normal file
@@ -0,0 +1,42 @@
|
||||
# CONFIG_SITE
|
||||
|
||||
# Make any application-specific changes to the EPICS build
|
||||
# configuration variables in this file.
|
||||
#
|
||||
# Host/target specific settings can be specified in files named
|
||||
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
# CONFIG_SITE.Common.$(T_A)
|
||||
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
# CHECK_RELEASE controls the consistency checking of the support
|
||||
# applications pointed to by the RELEASE* files.
|
||||
# Normally CHECK_RELEASE should be set to YES.
|
||||
# Set CHECK_RELEASE to NO to disable checking completely.
|
||||
# Set CHECK_RELEASE to WARN to perform consistency checking but
|
||||
# continue building even if conflicts are found.
|
||||
CHECK_RELEASE = YES
|
||||
|
||||
# Set this when you only want to compile this application
|
||||
# for a subset of the cross-compiled target architectures
|
||||
# that Base is built for.
|
||||
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
|
||||
|
||||
# To install files into a location other than $(TOP) define
|
||||
# INSTALL_LOCATION here.
|
||||
#INSTALL_LOCATION=</absolute/path/to/install/top>
|
||||
|
||||
# Set this when the IOC and build host use different paths
|
||||
# to the install location. This may be needed to boot from
|
||||
# a Microsoft FTP server say, or on some NFS configurations.
|
||||
#IOCS_APPL_TOP = </IOC's/absolute/path/to/install/top>
|
||||
|
||||
# For application debugging purposes, override the HOST_OPT and/
|
||||
# or CROSS_OPT settings from base/configure/CONFIG_SITE
|
||||
#HOST_OPT = NO
|
||||
#CROSS_OPT = NO
|
||||
|
||||
# These allow developers to override the CONFIG_SITE variable
|
||||
# settings without having to modify the configure/CONFIG_SITE
|
||||
# file itself.
|
||||
-include $(TOP)/../CONFIG_SITE.local
|
||||
-include $(TOP)/configure/CONFIG_SITE.local
|
||||
15
modules/libcom/configure/Makefile
Normal file
15
modules/libcom/configure/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
#*************************************************************************
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
TOP = ..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
CFG += CONFIG_LIBCOM_MODULE
|
||||
CFG += CONFIG_LIBCOM_VERSION
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
38
modules/libcom/configure/RELEASE
Normal file
38
modules/libcom/configure/RELEASE
Normal file
@@ -0,0 +1,38 @@
|
||||
# RELEASE - Location of external support modules
|
||||
#
|
||||
# IF YOU CHANGE ANY PATHS in this file or make API changes to
|
||||
# any modules it refers to, you should do a "make rebuild" in
|
||||
# this application's top level directory.
|
||||
#
|
||||
# The EPICS build process does not check dependencies against
|
||||
# any files from outside the application, so it is safest to
|
||||
# rebuild it completely if any modules it depends on change.
|
||||
#
|
||||
# Host- or target-specific settings can be given in files named
|
||||
# RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
# RELEASE.Common.$(T_A)
|
||||
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
#
|
||||
# This file is parsed by both GNUmake and an EPICS Perl script,
|
||||
# so it may ONLY contain definititions of paths to other support
|
||||
# modules, variable definitions that are used in module paths,
|
||||
# and include statements that pull in other RELEASE files.
|
||||
# Variables may be used before their values have been set.
|
||||
# Build variables that are NOT used in paths should be set in
|
||||
# the CONFIG_SITE file.
|
||||
|
||||
# Variables and paths to dependent modules:
|
||||
#MODULES = /path/to/modules
|
||||
#MYMODULE = $(MODULES)/my-module
|
||||
|
||||
# If building the EPICS modules individually, set these:
|
||||
#EPICS_BASE = $(MODULES)/core-7.0.1
|
||||
|
||||
# Set RULES here if you want to use build rules from elsewhere:
|
||||
#RULES = $(MODULES)/build-rules
|
||||
|
||||
# These lines allow developers to override these RELEASE settings
|
||||
# without having to modify this file directly.
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
6
modules/libcom/configure/RULES
Normal file
6
modules/libcom/configure/RULES
Normal file
@@ -0,0 +1,6 @@
|
||||
# RULES
|
||||
|
||||
include $(CONFIG)/RULES
|
||||
|
||||
# Library should be rebuilt because LIBOBJS may have changed.
|
||||
$(LIBNAME): ../Makefile
|
||||
2
modules/libcom/configure/RULES_DIRS
Normal file
2
modules/libcom/configure/RULES_DIRS
Normal file
@@ -0,0 +1,2 @@
|
||||
#RULES_DIRS
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
2
modules/libcom/configure/RULES_TOP
Normal file
2
modules/libcom/configure/RULES_TOP
Normal file
@@ -0,0 +1,2 @@
|
||||
#RULES_TOP
|
||||
include $(CONFIG)/RULES_TOP
|
||||
36
modules/libcom/src/Com.rc
Normal file
36
modules/libcom/src/Com.rc
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <winver.h>
|
||||
#include "epicsVersion.h"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION EPICS_VERSION,EPICS_REVISION,EPICS_MODIFICATION,EPICS_PATCH_LEVEL
|
||||
PRODUCTVERSION EPICS_VERSION,EPICS_REVISION,EPICS_MODIFICATION,EPICS_PATCH_LEVEL
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_UNKNOWN
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments","Common Library for EPICS\0"
|
||||
VALUE "CompanyName", "The EPICS collaboration\0"
|
||||
VALUE "FileDescription", "Common Library\0"
|
||||
VALUE "FileVersion", EPICS_VERSION_STRING "\0"
|
||||
VALUE "InternalName", "Com\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) Univ. of California, Univ. of Chicago\0"
|
||||
VALUE "OriginalFilename", "Com.dll\0"
|
||||
VALUE "ProductName", "Experimental Physics and Industrial Control System (EPICS)\0"
|
||||
VALUE "ProductVersion", EPICS_VERSION_STRING "\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
84
modules/libcom/src/Makefile
Normal file
84
modules/libcom/src/Makefile
Normal file
@@ -0,0 +1,84 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
# Uncomment this to remove the (benign) valgrind helper stubs
|
||||
#USR_CFLAGS += -DNVALGRIND
|
||||
|
||||
LIBCOM = $(TOP)/src
|
||||
|
||||
INC += valgrind/valgrind.h
|
||||
|
||||
INC += libComVersion.h
|
||||
INC += libComVersionNum.h
|
||||
|
||||
include $(LIBCOM)/as/Makefile
|
||||
include $(LIBCOM)/bucketLib/Makefile
|
||||
include $(LIBCOM)/calc/Makefile
|
||||
include $(LIBCOM)/cvtFast/Makefile
|
||||
include $(LIBCOM)/cppStd/Makefile
|
||||
include $(LIBCOM)/cxxTemplates/Makefile
|
||||
include $(LIBCOM)/dbmf/Makefile
|
||||
include $(LIBCOM)/ellLib/Makefile
|
||||
include $(LIBCOM)/env/Makefile
|
||||
include $(LIBCOM)/error/Makefile
|
||||
include $(LIBCOM)/fdmgr/Makefile
|
||||
include $(LIBCOM)/flex/Makefile
|
||||
include $(LIBCOM)/freeList/Makefile
|
||||
include $(LIBCOM)/gpHash/Makefile
|
||||
include $(LIBCOM)/iocsh/Makefile
|
||||
include $(LIBCOM)/log/Makefile
|
||||
include $(LIBCOM)/macLib/Makefile
|
||||
include $(LIBCOM)/misc/Makefile
|
||||
include $(LIBCOM)/osi/Makefile
|
||||
include $(LIBCOM)/pool/Makefile
|
||||
include $(LIBCOM)/ring/Makefile
|
||||
include $(LIBCOM)/taskwd/Makefile
|
||||
include $(LIBCOM)/timer/Makefile
|
||||
include $(LIBCOM)/yacc/Makefile
|
||||
include $(LIBCOM)/yajl/Makefile
|
||||
|
||||
# Library to build:
|
||||
LIBRARY=Com
|
||||
|
||||
Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
Com_RCS = Com.rc
|
||||
|
||||
ifeq ($(T_A),$(EPICS_HOST_ARCH))
|
||||
# Antelope & flex are needed to finish libCom
|
||||
DELAY_INSTALL_LIBS = YES
|
||||
endif
|
||||
|
||||
EXPANDVARS += EPICS_LIBCOM_MAJOR_VERSION
|
||||
EXPANDVARS += EPICS_LIBCOM_MINOR_VERSION
|
||||
EXPANDVARS += EPICS_LIBCOM_MAINTENANCE_VERSION
|
||||
EXPANDVARS += EPICS_LIBCOM_DEVELOPMENT_FLAG
|
||||
|
||||
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION = 3.17.0
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
include $(LIBCOM)/as/RULES
|
||||
include $(LIBCOM)/env/RULES
|
||||
include $(LIBCOM)/error/RULES
|
||||
include $(LIBCOM)/flex/RULES
|
||||
include $(LIBCOM)/misc/RULES
|
||||
include $(LIBCOM)/osi/RULES
|
||||
include $(LIBCOM)/yajl/RULES
|
||||
|
||||
# Can't use EXPAND as generated headers must appear
|
||||
# in O.Common, but EXPAND emits rules for O.$(T_A)
|
||||
../O.Common/libComVersionNum.h: ../libComVersionNum.h@
|
||||
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
22
modules/libcom/src/as/Makefile
Normal file
22
modules/libcom/src/as/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
|
||||
# Brookhaven National Lab.
|
||||
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/as
|
||||
|
||||
INC += asLib.h
|
||||
INC += asTrapWrite.h
|
||||
|
||||
Com_SRCS += asLib.c
|
||||
Com_SRCS += asTrapWrite.c
|
||||
|
||||
CLEANS += asLib.c asLib_lex.c
|
||||
21
modules/libcom/src/as/RULES
Normal file
21
modules/libcom/src/as/RULES
Normal file
@@ -0,0 +1,21 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
|
||||
# Brookhaven National Lab.
|
||||
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
# Extra rule since asLib_lex.c is included by asLib.c
|
||||
asLib$(DEP): asLib_lex.c
|
||||
asLib.c: asLib_lex.c
|
||||
|
||||
# Ensure that lexer and parser are built before they are needed
|
||||
asLib.c: $(INSTALL_HOST_BIN)/antelope$(HOSTEXE)
|
||||
asLib_lex.c: $(INSTALL_HOST_BIN)/e_flex$(HOSTEXE)
|
||||
asLib_lex.c: $(INSTALL_INCLUDE)/flex.skel.static
|
||||
244
modules/libcom/src/as/asLib.h
Normal file
244
modules/libcom/src/as/asLib.h
Normal file
@@ -0,0 +1,244 @@
|
||||
/* asLib.h */
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* Author: Marty Kraimer Date: 09-27-93*/
|
||||
|
||||
#ifndef INCasLibh
|
||||
#define INCasLibh
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "ellLib.h"
|
||||
#include "errMdef.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct asgMember *ASMEMBERPVT;
|
||||
typedef struct asgClient *ASCLIENTPVT;
|
||||
typedef int (*ASINPUTFUNCPTR)(char *buf,int max_size);
|
||||
typedef enum{
|
||||
asClientCOAR /*Change of access rights*/
|
||||
/*For now this is all*/
|
||||
} asClientStatus;
|
||||
|
||||
typedef void (*ASCLIENTCALLBACK) (ASCLIENTPVT,asClientStatus);
|
||||
|
||||
/* The following routines are macros with the following syntax
|
||||
long asCheckGet(ASCLIENTPVT asClientPvt);
|
||||
long asCheckPut(ASCLIENTPVT asClientPvt);
|
||||
*/
|
||||
#define asCheckGet(asClientPvt) \
|
||||
(!asActive || ((asClientPvt)->access >= asREAD))
|
||||
#define asCheckPut(asClientPvt) \
|
||||
(!asActive || ((asClientPvt)->access >= asWRITE))
|
||||
|
||||
/* More convenience macros
|
||||
void *asTrapWriteWithData(ASCLIENTPVT asClientPvt,
|
||||
const char *userid, const char *hostid, void *addr,
|
||||
int dbrType, int no_elements, void *data);
|
||||
void asTrapWriteAfter(ASCLIENTPVT asClientPvt);
|
||||
*/
|
||||
#define asTrapWriteWithData(asClientPvt, user, host, addr, type, count, data) \
|
||||
((asActive && (asClientPvt)->trapMask) \
|
||||
? asTrapWriteBeforeWithData((user), (host), (addr), (type), (count), (data)) \
|
||||
: 0)
|
||||
#define asTrapWriteAfter(pvt) \
|
||||
if (pvt) asTrapWriteAfterWrite(pvt)
|
||||
|
||||
/* This macro is for backwards compatibility, upgrade any code
|
||||
calling it to use asTrapWriteWithData() instead ASAP:
|
||||
void *asTrapWriteBefore(ASCLIENTPVT asClientPvt,
|
||||
const char *userid, const char *hostid, void *addr);
|
||||
*/
|
||||
#define asTrapWriteBefore(asClientPvt, user, host, addr) \
|
||||
asTrapWriteWithData(asClientPvt, user, host, addr, 0, 0, NULL)
|
||||
|
||||
|
||||
epicsShareFunc long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction);
|
||||
epicsShareFunc long epicsShareAPI asInitFile(
|
||||
const char *filename,const char *substitutions);
|
||||
epicsShareFunc long epicsShareAPI asInitFP(FILE *fp,const char *substitutions);
|
||||
/*caller must provide permanent storage for asgName*/
|
||||
epicsShareFunc long epicsShareAPI asAddMember(
|
||||
ASMEMBERPVT *asMemberPvt,const char *asgName);
|
||||
epicsShareFunc long epicsShareAPI asRemoveMember(ASMEMBERPVT *asMemberPvt);
|
||||
/*caller must provide permanent storage for newAsgName*/
|
||||
epicsShareFunc long epicsShareAPI asChangeGroup(
|
||||
ASMEMBERPVT *asMemberPvt,const char *newAsgName);
|
||||
epicsShareFunc void * epicsShareAPI asGetMemberPvt(ASMEMBERPVT asMemberPvt);
|
||||
epicsShareFunc void epicsShareAPI asPutMemberPvt(
|
||||
ASMEMBERPVT asMemberPvt,void *userPvt);
|
||||
/*client must provide permanent storage for user and host*/
|
||||
epicsShareFunc long epicsShareAPI asAddClient(
|
||||
ASCLIENTPVT *asClientPvt,ASMEMBERPVT asMemberPvt,
|
||||
int asl,const char *user,char *host);
|
||||
/*client must provide permanent storage for user and host*/
|
||||
epicsShareFunc long epicsShareAPI asChangeClient(
|
||||
ASCLIENTPVT asClientPvt,int asl,const char *user,char *host);
|
||||
epicsShareFunc long epicsShareAPI asRemoveClient(ASCLIENTPVT *asClientPvt);
|
||||
epicsShareFunc void * epicsShareAPI asGetClientPvt(ASCLIENTPVT asClientPvt);
|
||||
epicsShareFunc void epicsShareAPI asPutClientPvt(
|
||||
ASCLIENTPVT asClientPvt,void *userPvt);
|
||||
epicsShareFunc long epicsShareAPI asRegisterClientCallback(
|
||||
ASCLIENTPVT asClientPvt, ASCLIENTCALLBACK pcallback);
|
||||
epicsShareFunc long epicsShareAPI asComputeAllAsg(void);
|
||||
/* following declared below after ASG is declared
|
||||
epicsShareFunc long epicsShareAPI asComputeAsg(ASG *pasg);
|
||||
*/
|
||||
epicsShareFunc long epicsShareAPI asCompute(ASCLIENTPVT asClientPvt);
|
||||
epicsShareFunc int epicsShareAPI asDump(
|
||||
void (*memcallback)(ASMEMBERPVT,FILE *),
|
||||
void (*clientcallback)(ASCLIENTPVT,FILE *),int verbose);
|
||||
epicsShareFunc int epicsShareAPI asDumpFP(FILE *fp,
|
||||
void (*memcallback)(ASMEMBERPVT,FILE *),
|
||||
void (*clientcallback)(ASCLIENTPVT,FILE *),int verbose);
|
||||
epicsShareFunc int epicsShareAPI asDumpUag(const char *uagname);
|
||||
epicsShareFunc int epicsShareAPI asDumpUagFP(FILE *fp,const char *uagname);
|
||||
epicsShareFunc int epicsShareAPI asDumpHag(const char *hagname);
|
||||
epicsShareFunc int epicsShareAPI asDumpHagFP(FILE *fp,const char *hagname);
|
||||
epicsShareFunc int epicsShareAPI asDumpRules(const char *asgname);
|
||||
epicsShareFunc int epicsShareAPI asDumpRulesFP(FILE *fp,const char *asgname);
|
||||
epicsShareFunc int epicsShareAPI asDumpMem(const char *asgname,
|
||||
void (*memcallback)(ASMEMBERPVT,FILE *),int clients);
|
||||
epicsShareFunc int epicsShareAPI asDumpMemFP(FILE *fp,const char *asgname,
|
||||
void (*memcallback)(ASMEMBERPVT,FILE *),int clients);
|
||||
epicsShareFunc int epicsShareAPI asDumpHash(void);
|
||||
epicsShareFunc int epicsShareAPI asDumpHashFP(FILE *fp);
|
||||
|
||||
epicsShareFunc void * epicsShareAPI asTrapWriteBeforeWithData(
|
||||
const char *userid, const char *hostid, void *addr,
|
||||
int dbrType, int no_elements, void *data);
|
||||
|
||||
epicsShareFunc void epicsShareAPI asTrapWriteAfterWrite(void *pvt);
|
||||
|
||||
#define S_asLib_clientsExist (M_asLib| 1) /*Client Exists*/
|
||||
#define S_asLib_noUag (M_asLib| 2) /*User Access Group does not exist*/
|
||||
#define S_asLib_noHag (M_asLib| 3) /*Host Access Group does not exist*/
|
||||
#define S_asLib_noAccess (M_asLib| 4) /*access security: no access allowed*/
|
||||
#define S_asLib_noModify (M_asLib| 5) /*access security: no modification allowed*/
|
||||
#define S_asLib_badConfig (M_asLib| 6) /*access security: bad configuration file*/
|
||||
#define S_asLib_badCalc (M_asLib| 7) /*access security: bad calculation espression*/
|
||||
#define S_asLib_dupAsg (M_asLib| 8) /*Duplicate Access Security Group */
|
||||
#define S_asLib_InitFailed (M_asLib| 9) /*access security: Init failed*/
|
||||
#define S_asLib_asNotActive (M_asLib|10) /*access security is not active*/
|
||||
#define S_asLib_badMember (M_asLib|11) /*access security: bad ASMEMBERPVT*/
|
||||
#define S_asLib_badClient (M_asLib|12) /*access security: bad ASCLIENTPVT*/
|
||||
#define S_asLib_badAsg (M_asLib|13) /*access security: bad ASG*/
|
||||
#define S_asLib_noMemory (M_asLib|14) /*access security: no Memory */
|
||||
|
||||
/*Private declarations */
|
||||
epicsShareExtern int asActive;
|
||||
|
||||
/* definition of access rights*/
|
||||
typedef enum{asNOACCESS,asREAD,asWRITE} asAccessRights;
|
||||
|
||||
struct gphPvt;
|
||||
|
||||
/*Base pointers for access security*/
|
||||
typedef struct asBase{
|
||||
ELLLIST uagList;
|
||||
ELLLIST hagList;
|
||||
ELLLIST asgList;
|
||||
struct gphPvt *phash;
|
||||
} ASBASE;
|
||||
|
||||
epicsShareExtern volatile ASBASE *pasbase;
|
||||
|
||||
/*Defs for User Access Groups*/
|
||||
typedef struct{
|
||||
ELLNODE node;
|
||||
char *user;
|
||||
} UAGNAME;
|
||||
typedef struct uag{
|
||||
ELLNODE node;
|
||||
char *name;
|
||||
ELLLIST list; /*list of UAGNAME*/
|
||||
} UAG;
|
||||
/*Defs for Host Access Groups*/
|
||||
typedef struct{
|
||||
ELLNODE node;
|
||||
char *host;
|
||||
} HAGNAME;
|
||||
typedef struct hag{
|
||||
ELLNODE node;
|
||||
char *name;
|
||||
ELLLIST list; /*list of HAGNAME*/
|
||||
} HAG;
|
||||
/*Defs for Access SecurityGroups*/
|
||||
typedef struct {
|
||||
ELLNODE node;
|
||||
UAG *puag;
|
||||
}ASGUAG;
|
||||
typedef struct {
|
||||
ELLNODE node;
|
||||
HAG *phag;
|
||||
}ASGHAG;
|
||||
#define AS_TRAP_WRITE 1
|
||||
typedef struct{
|
||||
ELLNODE node;
|
||||
asAccessRights access;
|
||||
int level;
|
||||
unsigned long inpUsed; /*bitmap of which inputs are used*/
|
||||
int result; /*Result of calc converted to TRUE/FALSE*/
|
||||
char *calc;
|
||||
void *rpcl;
|
||||
ELLLIST uagList; /*List of ASGUAG*/
|
||||
ELLLIST hagList; /*List of ASGHAG*/
|
||||
int trapMask;
|
||||
} ASGRULE;
|
||||
typedef struct{
|
||||
ELLNODE node;
|
||||
char *inp;
|
||||
void *capvt;
|
||||
struct asg *pasg;
|
||||
int inpIndex;
|
||||
}ASGINP;
|
||||
|
||||
typedef struct asg{
|
||||
ELLNODE node;
|
||||
char *name;
|
||||
ELLLIST inpList;
|
||||
ELLLIST ruleList;
|
||||
ELLLIST memberList;
|
||||
double *pavalue; /*pointer to array of input values*/
|
||||
unsigned long inpBad; /*bitmap of which inputs are bad*/
|
||||
unsigned long inpChanged; /*bitmap of inputs that changed*/
|
||||
} ASG;
|
||||
typedef struct asgMember {
|
||||
ELLNODE node;
|
||||
ASG *pasg;
|
||||
ELLLIST clientList;
|
||||
const char *asgName;
|
||||
void *userPvt;
|
||||
} ASGMEMBER;
|
||||
|
||||
typedef struct asgClient {
|
||||
ELLNODE node;
|
||||
ASGMEMBER *pasgMember;
|
||||
const char *user;
|
||||
char *host;
|
||||
void *userPvt;
|
||||
ASCLIENTCALLBACK pcallback;
|
||||
int level;
|
||||
asAccessRights access;
|
||||
int trapMask;
|
||||
} ASGCLIENT;
|
||||
|
||||
epicsShareFunc long epicsShareAPI asComputeAsg(ASG *pasg);
|
||||
/*following is "friend" function*/
|
||||
epicsShareFunc void * epicsShareAPI asCalloc(size_t nobj,size_t size);
|
||||
epicsShareFunc char * epicsShareAPI asStrdup(unsigned char *str);
|
||||
epicsShareFunc void asFreeAll(ASBASE *pasbase);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCasLibh*/
|
||||
230
modules/libcom/src/as/asLib.y
Normal file
230
modules/libcom/src/as/asLib.y
Normal file
@@ -0,0 +1,230 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
%{
|
||||
static int yyerror(char *);
|
||||
static int yy_start;
|
||||
#include "asLibRoutines.c"
|
||||
static int yyFailed = FALSE;
|
||||
static int line_num=1;
|
||||
static UAG *yyUag=NULL;
|
||||
static HAG *yyHag=NULL;
|
||||
static ASG *yyAsg=NULL;
|
||||
static ASGRULE *yyAsgRule=NULL;
|
||||
%}
|
||||
|
||||
%start asconfig
|
||||
|
||||
%token tokenUAG tokenHAG tokenASG tokenRULE tokenCALC
|
||||
%token <Str> tokenINP
|
||||
%token <Int> tokenINTEGER
|
||||
%token <Str> tokenSTRING
|
||||
|
||||
%union
|
||||
{
|
||||
int Int;
|
||||
char *Str;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
asconfig: asconfig asconfig_item
|
||||
| asconfig_item
|
||||
|
||||
asconfig_item: tokenUAG uag_head uag_body
|
||||
| tokenUAG uag_head
|
||||
| tokenHAG hag_head hag_body
|
||||
| tokenHAG hag_head
|
||||
| tokenASG asg_head asg_body
|
||||
| tokenASG asg_head
|
||||
;
|
||||
|
||||
uag_head: '(' tokenSTRING ')'
|
||||
{
|
||||
yyUag = asUagAdd($2);
|
||||
if(!yyUag) yyerror("");
|
||||
free((void *)$2);
|
||||
}
|
||||
;
|
||||
|
||||
uag_body: '{' uag_user_list '}'
|
||||
{
|
||||
;
|
||||
}
|
||||
;
|
||||
|
||||
uag_user_list: uag_user_list ',' uag_user_list_name
|
||||
| uag_user_list_name
|
||||
;
|
||||
|
||||
uag_user_list_name: tokenSTRING
|
||||
{
|
||||
if (asUagAddUser(yyUag,$1))
|
||||
yyerror("");
|
||||
free((void *)$1);
|
||||
}
|
||||
;
|
||||
|
||||
hag_head: '(' tokenSTRING ')'
|
||||
{
|
||||
yyHag = asHagAdd($2);
|
||||
if(!yyHag) yyerror("");
|
||||
free((void *)$2);
|
||||
}
|
||||
;
|
||||
|
||||
hag_body: '{' hag_host_list '}'
|
||||
;
|
||||
|
||||
hag_host_list: hag_host_list ',' hag_host_list_name
|
||||
| hag_host_list_name
|
||||
;
|
||||
|
||||
hag_host_list_name: tokenSTRING
|
||||
{
|
||||
if (asHagAddHost(yyHag,$1))
|
||||
yyerror("");
|
||||
free((void *)$1);
|
||||
}
|
||||
;
|
||||
|
||||
asg_head: '(' tokenSTRING ')'
|
||||
{
|
||||
yyAsg = asAsgAdd($2);
|
||||
if(!yyAsg) yyerror("");
|
||||
free((void *)$2);
|
||||
}
|
||||
;
|
||||
|
||||
asg_body: '{' asg_body_list '}'
|
||||
{
|
||||
}
|
||||
|
||||
asg_body_list: asg_body_list asg_body_item
|
||||
| asg_body_item
|
||||
|
||||
asg_body_item: inp_config | rule_config
|
||||
;
|
||||
|
||||
inp_config: tokenINP '(' tokenSTRING ')'
|
||||
{
|
||||
if (asAsgAddInp(yyAsg,$3,$<Int>1))
|
||||
yyerror("");
|
||||
free((void *)$3);
|
||||
}
|
||||
;
|
||||
|
||||
rule_config: tokenRULE rule_head rule_body
|
||||
| tokenRULE rule_head
|
||||
|
||||
rule_head: rule_head_manditory rule_head_options
|
||||
|
||||
rule_head_manditory: '(' tokenINTEGER ',' tokenSTRING
|
||||
{
|
||||
asAccessRights rights;
|
||||
|
||||
if((strcmp($4,"NONE")==0)) {
|
||||
rights=asNOACCESS;
|
||||
} else if((strcmp($4,"READ")==0)) {
|
||||
rights=asREAD;
|
||||
} else if((strcmp($4,"WRITE")==0)) {
|
||||
rights=asWRITE;
|
||||
} else {
|
||||
yyerror("Access rights must be NONE, READ or WRITE");
|
||||
rights = asNOACCESS;
|
||||
}
|
||||
yyAsgRule = asAsgAddRule(yyAsg,rights,$2);
|
||||
free((void *)$4);
|
||||
}
|
||||
;
|
||||
|
||||
rule_head_options: ')'
|
||||
| rule_log_options
|
||||
|
||||
rule_log_options: ',' tokenSTRING ')'
|
||||
{
|
||||
if((strcmp($2,"TRAPWRITE")==0)) {
|
||||
long status;
|
||||
status = asAsgAddRuleOptions(yyAsgRule,AS_TRAP_WRITE);
|
||||
if(status) yyerror("");
|
||||
} else if((strcmp($2,"NOTRAPWRITE")!=0)) {
|
||||
yyerror("Log options must be TRAPWRITE or NOTRAPWRITE");
|
||||
}
|
||||
free((void *)$2);
|
||||
}
|
||||
;
|
||||
|
||||
rule_body: '{' rule_list '}'
|
||||
;
|
||||
|
||||
rule_list: rule_list rule_list_item
|
||||
| rule_list_item
|
||||
;
|
||||
|
||||
rule_list_item: tokenUAG '(' rule_uag_list ')'
|
||||
| tokenHAG '(' rule_hag_list ')'
|
||||
| tokenCALC '(' tokenSTRING ')'
|
||||
{
|
||||
if (asAsgRuleCalc(yyAsgRule,$3))
|
||||
yyerror("");
|
||||
free((void *)$3);
|
||||
}
|
||||
;
|
||||
|
||||
rule_uag_list: rule_uag_list ',' rule_uag_list_name
|
||||
| rule_uag_list_name
|
||||
;
|
||||
|
||||
rule_uag_list_name: tokenSTRING
|
||||
{
|
||||
if (asAsgRuleUagAdd(yyAsgRule,$1))
|
||||
yyerror("");
|
||||
free((void *)$1);
|
||||
}
|
||||
;
|
||||
|
||||
rule_hag_list: rule_hag_list ',' rule_hag_list_name
|
||||
| rule_hag_list_name
|
||||
;
|
||||
|
||||
rule_hag_list_name: tokenSTRING
|
||||
{
|
||||
if (asAsgRuleHagAdd(yyAsgRule,$1))
|
||||
yyerror("");
|
||||
free((void *)$1);
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
||||
#include "asLib_lex.c"
|
||||
|
||||
static int yyerror(char *str)
|
||||
{
|
||||
if (strlen(str))
|
||||
errlogPrintf("%s at line %d\n", str, line_num);
|
||||
else
|
||||
errlogPrintf("Error at line %d\n", line_num);
|
||||
yyFailed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
static int myParse(ASINPUTFUNCPTR inputfunction)
|
||||
{
|
||||
static int FirstFlag = 1;
|
||||
int rtnval;
|
||||
|
||||
my_yyinput = &inputfunction;
|
||||
if (!FirstFlag) {
|
||||
line_num=1;
|
||||
yyFailed = FALSE;
|
||||
yyreset();
|
||||
yyrestart(NULL);
|
||||
}
|
||||
FirstFlag = 0;
|
||||
rtnval = yyparse();
|
||||
if(rtnval!=0 || yyFailed) return(-1); else return(0);
|
||||
}
|
||||
1352
modules/libcom/src/as/asLibRoutines.c
Normal file
1352
modules/libcom/src/as/asLibRoutines.c
Normal file
File diff suppressed because it is too large
Load Diff
94
modules/libcom/src/as/asLib_lex.l
Normal file
94
modules/libcom/src/as/asLib_lex.l
Normal file
@@ -0,0 +1,94 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
newline "\n"
|
||||
backslash "\\"
|
||||
doublequote "\""
|
||||
comment "#"
|
||||
whitespace [ \t\r]
|
||||
escape {backslash}.
|
||||
stringchar [^"\n\\]
|
||||
|
||||
name [a-zA-Z0-9_\-+:.\[\]<>;]
|
||||
digit [0-9]
|
||||
punctuation [(){},]
|
||||
link [A-L]
|
||||
|
||||
%{
|
||||
static ASINPUTFUNCPTR *my_yyinput;
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(b,r,ms) (r=(*my_yyinput)((char *)b,ms))
|
||||
|
||||
static int yyreset(void)
|
||||
{
|
||||
line_num=1;
|
||||
BEGIN INITIAL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
UAG { return(tokenUAG); }
|
||||
HAG { return(tokenHAG); }
|
||||
ASG { return(tokenASG); }
|
||||
RULE { return(tokenRULE); }
|
||||
CALC { return(tokenCALC); }
|
||||
|
||||
INP{link} {
|
||||
yylval.Int = (unsigned char)yytext[3];
|
||||
yylval.Int -= 'A';
|
||||
return(tokenINP);
|
||||
}
|
||||
|
||||
{digit}+ { /*integer*/
|
||||
yylval.Int = atoi((char *)yytext);
|
||||
return(tokenINTEGER);
|
||||
}
|
||||
|
||||
{name}+ { /*unquoted string*/
|
||||
yylval.Str=asStrdup(yytext);
|
||||
return(tokenSTRING);
|
||||
}
|
||||
|
||||
{doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */
|
||||
yylval.Str=asStrdup(yytext+1);
|
||||
yylval.Str[strlen(yylval.Str)-1] = '\0';
|
||||
return(tokenSTRING);
|
||||
}
|
||||
|
||||
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
|
||||
yyerror("Newline in quoted string, closing quote missing");
|
||||
}
|
||||
|
||||
{punctuation} { return(yytext[0]); }
|
||||
|
||||
{newline} { line_num++; }
|
||||
|
||||
{comment}.* ;
|
||||
{whitespace} ;
|
||||
|
||||
. {
|
||||
char message[40];
|
||||
YY_BUFFER_STATE *dummy=0;
|
||||
|
||||
if (isprint((int) yytext[0])) {
|
||||
sprintf(message, "Invalid character '%c'", yytext[0]);
|
||||
}
|
||||
else {
|
||||
sprintf(message, "Invalid character 0x%2.2x", yytext[0]);
|
||||
}
|
||||
yyerror(message);
|
||||
|
||||
/*The following suppress compiler warning messages*/
|
||||
if (0) yyunput('c',(unsigned char *) message);
|
||||
if (0) yy_switch_to_buffer(*dummy);
|
||||
}
|
||||
|
||||
%%
|
||||
175
modules/libcom/src/as/asTrapWrite.c
Normal file
175
modules/libcom/src/as/asTrapWrite.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*asTrapWrite.c */
|
||||
/* Author: Marty Kraimer Date: 07NOV2000 */
|
||||
|
||||
/* Matthias Clausen and Vladis Korobov at DESY
|
||||
* implemented the first logging of Channel Access Puts
|
||||
* This implementation uses many ideas from their implementation
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "ellLib.h"
|
||||
#include "freeList.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "ellLib.h"
|
||||
|
||||
#include "asLib.h"
|
||||
#include "asTrapWrite.h"
|
||||
|
||||
typedef struct listenerPvt {
|
||||
ELLNODE node;
|
||||
struct listener *plistener;
|
||||
void *userPvt;
|
||||
}listenerPvt;
|
||||
|
||||
typedef struct listener{
|
||||
ELLNODE node;
|
||||
asTrapWriteListener func;
|
||||
}listener;
|
||||
|
||||
typedef struct writeMessage {
|
||||
ELLNODE node;
|
||||
asTrapWriteMessage message;
|
||||
ELLLIST listenerPvtList;
|
||||
}writeMessage;
|
||||
|
||||
|
||||
typedef struct asTrapWritePvt
|
||||
{
|
||||
ELLLIST listenerList;
|
||||
ELLLIST writeMessageList;
|
||||
void *freeListWriteMessage;
|
||||
void *freeListListenerPvt;
|
||||
epicsMutexId lock;
|
||||
}asTrapWritePvt;
|
||||
|
||||
static asTrapWritePvt *pasTrapWritePvt = 0;
|
||||
|
||||
static void asTrapWriteInit(void)
|
||||
{
|
||||
pasTrapWritePvt = callocMustSucceed(1,sizeof(asTrapWritePvt),"asTrapWriteInit");
|
||||
ellInit(&pasTrapWritePvt->listenerList);
|
||||
ellInit(&pasTrapWritePvt->writeMessageList);
|
||||
freeListInitPvt(
|
||||
&pasTrapWritePvt->freeListWriteMessage,sizeof(writeMessage),20);
|
||||
freeListInitPvt(
|
||||
&pasTrapWritePvt->freeListListenerPvt,sizeof(listenerPvt),20);
|
||||
pasTrapWritePvt->lock = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
asTrapWriteId epicsShareAPI asTrapWriteRegisterListener(
|
||||
asTrapWriteListener func)
|
||||
{
|
||||
listener *plistener;
|
||||
if(pasTrapWritePvt==0) asTrapWriteInit();
|
||||
plistener = callocMustSucceed(1,sizeof(listener),"asTrapWriteRegisterListener");
|
||||
plistener->func = func;
|
||||
epicsMutexMustLock(pasTrapWritePvt->lock);
|
||||
ellAdd(&pasTrapWritePvt->listenerList,&plistener->node);
|
||||
epicsMutexUnlock(pasTrapWritePvt->lock);
|
||||
return((asTrapWriteId)plistener);
|
||||
}
|
||||
|
||||
void epicsShareAPI asTrapWriteUnregisterListener(asTrapWriteId id)
|
||||
{
|
||||
listener *plistener = (listener *)id;
|
||||
writeMessage *pwriteMessage;
|
||||
|
||||
if(pasTrapWritePvt==0) return;
|
||||
epicsMutexMustLock(pasTrapWritePvt->lock);
|
||||
pwriteMessage = (writeMessage *)ellFirst(&pasTrapWritePvt->writeMessageList);
|
||||
while(pwriteMessage) {
|
||||
listenerPvt *plistenerPvt
|
||||
= (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList);
|
||||
while(plistenerPvt) {
|
||||
listenerPvt *pnext
|
||||
= (listenerPvt *)ellNext(&plistenerPvt->node);
|
||||
if(plistenerPvt->plistener == plistener) {
|
||||
ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node);
|
||||
freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt);
|
||||
}
|
||||
plistenerPvt = pnext;
|
||||
}
|
||||
pwriteMessage = (writeMessage *)ellNext(&pwriteMessage->node);
|
||||
}
|
||||
ellDelete(&pasTrapWritePvt->listenerList,&plistener->node);
|
||||
free(plistener);
|
||||
epicsMutexUnlock(pasTrapWritePvt->lock);
|
||||
}
|
||||
|
||||
void * epicsShareAPI asTrapWriteBeforeWithData(
|
||||
const char *userid, const char *hostid, void *addr,
|
||||
int dbrType, int no_elements, void *data)
|
||||
{
|
||||
writeMessage *pwriteMessage;
|
||||
listener *plistener;
|
||||
|
||||
if (pasTrapWritePvt == 0 ||
|
||||
ellCount(&pasTrapWritePvt->listenerList) <= 0) return 0;
|
||||
|
||||
pwriteMessage = (writeMessage *)freeListCalloc(
|
||||
pasTrapWritePvt->freeListWriteMessage);
|
||||
pwriteMessage->message.userid = userid;
|
||||
pwriteMessage->message.hostid = hostid;
|
||||
pwriteMessage->message.serverSpecific = addr;
|
||||
pwriteMessage->message.dbrType = dbrType;
|
||||
pwriteMessage->message.no_elements = no_elements;
|
||||
pwriteMessage->message.data = data;
|
||||
ellInit(&pwriteMessage->listenerPvtList);
|
||||
|
||||
epicsMutexMustLock(pasTrapWritePvt->lock);
|
||||
ellAdd(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node);
|
||||
plistener = (listener *)ellFirst(&pasTrapWritePvt->listenerList);
|
||||
while (plistener) {
|
||||
listenerPvt *plistenerPvt = (listenerPvt *)freeListCalloc(
|
||||
pasTrapWritePvt->freeListListenerPvt);
|
||||
|
||||
plistenerPvt->plistener = plistener;
|
||||
pwriteMessage->message.userPvt = 0;
|
||||
plistener->func(&pwriteMessage->message, 0);
|
||||
plistenerPvt->userPvt = pwriteMessage->message.userPvt;
|
||||
ellAdd(&pwriteMessage->listenerPvtList, &plistenerPvt->node);
|
||||
plistener = (listener *)ellNext(&plistener->node);
|
||||
}
|
||||
epicsMutexUnlock(pasTrapWritePvt->lock);
|
||||
return pwriteMessage;
|
||||
}
|
||||
|
||||
void epicsShareAPI asTrapWriteAfterWrite(void *pvt)
|
||||
{
|
||||
writeMessage *pwriteMessage = (writeMessage *)pvt;
|
||||
listenerPvt *plistenerPvt;
|
||||
|
||||
if (pwriteMessage == 0 ||
|
||||
pasTrapWritePvt == 0) return;
|
||||
|
||||
epicsMutexMustLock(pasTrapWritePvt->lock);
|
||||
plistenerPvt = (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList);
|
||||
while (plistenerPvt) {
|
||||
listenerPvt *pnext = (listenerPvt *)ellNext(&plistenerPvt->node);
|
||||
listener *plistener = plistenerPvt->plistener;
|
||||
|
||||
pwriteMessage->message.userPvt = plistenerPvt->userPvt;
|
||||
plistener->func(&pwriteMessage->message, 1);
|
||||
ellDelete(&pwriteMessage->listenerPvtList, &plistenerPvt->node);
|
||||
freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt);
|
||||
plistenerPvt = pnext;
|
||||
}
|
||||
ellDelete(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node);
|
||||
freeListFree(pasTrapWritePvt->freeListWriteMessage, pwriteMessage);
|
||||
epicsMutexUnlock(pasTrapWritePvt->lock);
|
||||
}
|
||||
56
modules/libcom/src/as/asTrapWrite.h
Normal file
56
modules/libcom/src/as/asTrapWrite.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*asTrapWrite.h*/
|
||||
/* Author: Marty Kraimer Date: 07NOV2000 */
|
||||
|
||||
#ifndef INCasTrapWriteh
|
||||
#define INCasTrapWriteh
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct asTrapWriteMessage {
|
||||
const char *userid;
|
||||
const char *hostid;
|
||||
void *serverSpecific;
|
||||
void *userPvt;
|
||||
int dbrType; /* Data type from ca/db_access.h, NOT dbFldTypes.h */
|
||||
int no_elements;
|
||||
void *data; /* Might be NULL if no data is available */
|
||||
} asTrapWriteMessage;
|
||||
|
||||
|
||||
typedef void *asTrapWriteId;
|
||||
typedef void(*asTrapWriteListener)(asTrapWriteMessage *pmessage,int after);
|
||||
|
||||
epicsShareFunc asTrapWriteId epicsShareAPI asTrapWriteRegisterListener(
|
||||
asTrapWriteListener func);
|
||||
epicsShareFunc void epicsShareAPI asTrapWriteUnregisterListener(
|
||||
asTrapWriteId id);
|
||||
|
||||
/*
|
||||
* asTrapWriteListener is called before and after the write is performed.
|
||||
* The listener can set userPvt on the before call and retrieve it after
|
||||
* after = (0,1) (before,after) the put.
|
||||
*
|
||||
* Each asTrapWriteMessage can change or may be deleted after
|
||||
* the user's asTrapWriteListener returns
|
||||
*
|
||||
* asTrapWriteListener delays the associated server thread so it must not
|
||||
* do anything that causes to to block.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCasTrapWriteh*/
|
||||
12
modules/libcom/src/bucketLib/Makefile
Normal file
12
modules/libcom/src/bucketLib/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/bucketLib
|
||||
INC += bucketLib.h
|
||||
Com_SRCS += bucketLib.c
|
||||
522
modules/libcom/src/bucketLib/bucketLib.c
Normal file
522
modules/libcom/src/bucketLib/bucketLib.c
Normal file
@@ -0,0 +1,522 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
* hill@atdiv.lanl.gov
|
||||
* (505) 665 1831
|
||||
* Date: 9-93
|
||||
*
|
||||
* NOTES:
|
||||
* .01 Storage for identifier must persist until an item is deleted
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "freeList.h" /* bucketLib uses freeListLib inside the DLL */
|
||||
#include "bucketLib.h"
|
||||
|
||||
/*
|
||||
* these data type dependent routines are
|
||||
* provided in the bucketLib.c
|
||||
*/
|
||||
typedef BUCKETID bucketHash(BUCKET *pb, const void *pId);
|
||||
typedef ITEM **bucketCompare(ITEM **ppi, const void *pId);
|
||||
|
||||
static bucketCompare bucketUnsignedCompare;
|
||||
static bucketCompare bucketPointerCompare;
|
||||
static bucketCompare bucketStringCompare;
|
||||
static bucketHash bucketUnsignedHash;
|
||||
static bucketHash bucketPointerHash;
|
||||
static bucketHash bucketStringHash;
|
||||
|
||||
typedef struct {
|
||||
bucketHash *pHash;
|
||||
bucketCompare *pCompare;
|
||||
buckTypeOfId type;
|
||||
}bucketSET;
|
||||
|
||||
static bucketSET BSET[] = {
|
||||
{bucketUnsignedHash, bucketUnsignedCompare, bidtUnsigned},
|
||||
{bucketPointerHash, bucketPointerCompare, bidtPointer},
|
||||
{bucketStringHash, bucketStringCompare, bidtString}
|
||||
};
|
||||
|
||||
static int bucketAddItem(BUCKET *prb, bucketSET *pBSET,
|
||||
const void *pId, const void *pApp);
|
||||
static void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucket id bit width
|
||||
*/
|
||||
#define BUCKETID_BIT_WIDTH (sizeof(BUCKETID)*CHAR_BIT)
|
||||
|
||||
/*
|
||||
* Maximum bucket size
|
||||
*/
|
||||
#define BUCKET_MAX_WIDTH 12
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedCompare()
|
||||
*/
|
||||
static ITEM **bucketUnsignedCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
unsigned id;
|
||||
unsigned *pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
id = * (unsigned *) pId;
|
||||
while ( (pi = *ppi) ) {
|
||||
if (bidtUnsigned == pi->type) {
|
||||
pItemId = (unsigned *) pi->pId;
|
||||
if (id == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerCompare()
|
||||
*/
|
||||
static ITEM **bucketPointerCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
void *ptr;
|
||||
void **pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
ptr = * (void **) pId;
|
||||
while ( (pi = *ppi) ) {
|
||||
if (bidtPointer == pi->type ) {
|
||||
pItemId = (void **) pi->pId;
|
||||
if (ptr == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringCompare ()
|
||||
*/
|
||||
static ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
ITEM *pi;
|
||||
int status;
|
||||
|
||||
while ( (pi = *ppi) ) {
|
||||
if (bidtString == pi->type) {
|
||||
status = strcmp (pStr, (char *)pi->pId);
|
||||
if (status == '\0') {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedHash ()
|
||||
*/
|
||||
static BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const unsigned *pUId = (const unsigned *) pId;
|
||||
unsigned src;
|
||||
BUCKETID hashid;
|
||||
|
||||
src = *pUId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while (src) {
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerHash ()
|
||||
*/
|
||||
static BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
void * const *ppId = (void * const *) pId;
|
||||
size_t src;
|
||||
BUCKETID hashid;
|
||||
|
||||
/*
|
||||
* This makes the assumption that size_t
|
||||
* can be used to hold a pointer value
|
||||
* (this assumption may not port to all
|
||||
* CPU architectures)
|
||||
*/
|
||||
src = (size_t) *ppId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while(src){
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringHash ()
|
||||
*/
|
||||
static BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const char *pStr = (const char *) pId;
|
||||
BUCKETID hashid;
|
||||
unsigned i;
|
||||
|
||||
hashid = 0;
|
||||
i = 1;
|
||||
while(*pStr){
|
||||
hashid += *pStr * i;
|
||||
pStr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
hashid = hashid % (pb->hashIdMask+1);
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketCreate()
|
||||
*/
|
||||
epicsShareFunc BUCKET * epicsShareAPI bucketCreate (unsigned nHashTableEntries)
|
||||
{
|
||||
BUCKETID mask;
|
||||
unsigned nbits;
|
||||
BUCKET *pb;
|
||||
|
||||
/*
|
||||
* no absurd sized buckets
|
||||
*/
|
||||
if (nHashTableEntries<=1) {
|
||||
fprintf (stderr, "Tiny bucket create failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* count the number of bits in the bucket id
|
||||
*/
|
||||
if ( BUCKETID_BIT_WIDTH > 0 ) {
|
||||
for (nbits=0; nbits<BUCKETID_BIT_WIDTH; nbits++) {
|
||||
mask = (1<<nbits) - 1;
|
||||
if ( ((nHashTableEntries-1) & ~mask) == 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mask = 0;
|
||||
nbits = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* indexWidth must be specified at least one
|
||||
* bit less than the bit size of type BUCKETID
|
||||
*/
|
||||
if (nbits>=BUCKETID_BIT_WIDTH) {
|
||||
fprintf (
|
||||
stderr,
|
||||
"%s at %d: Requested index width=%d to large. max=%ld\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
nbits,
|
||||
(long)(BUCKETID_BIT_WIDTH-1));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pb = (BUCKET *) calloc(1, sizeof(*pb));
|
||||
if (!pb) {
|
||||
return pb;
|
||||
}
|
||||
|
||||
pb->hashIdMask = mask;
|
||||
pb->hashIdNBits = nbits;
|
||||
freeListInitPvt(&pb->freeListPVT, sizeof(ITEM), 1024);
|
||||
|
||||
pb->pTable = (ITEM **) calloc (mask+1, sizeof(*pb->pTable));
|
||||
if (!pb->pTable) {
|
||||
freeListCleanup(pb->freeListPVT);
|
||||
free (pb);
|
||||
return NULL;
|
||||
}
|
||||
return pb;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketFree()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI bucketFree (BUCKET *prb)
|
||||
{
|
||||
/*
|
||||
* deleting a bucket with entries in use
|
||||
* will cause memory leaks and is not allowed
|
||||
*/
|
||||
assert (prb->nInUse==0);
|
||||
|
||||
/*
|
||||
* free the free list
|
||||
*/
|
||||
freeListCleanup(prb->freeListPVT);
|
||||
free (prb->pTable);
|
||||
free (prb);
|
||||
|
||||
return S_bucket_success;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketAddItem()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, const void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtUnsigned], pId, pApp);
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketAddItemPointerId(BUCKET *prb, void * const *pId, const void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtPointer], pId, pApp);
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketAddItemStringId(BUCKET *prb, const char *pId, const void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtString], pId, pApp);
|
||||
}
|
||||
static int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, const void *pApp)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
ITEM **ppiExists;
|
||||
ITEM *pi;
|
||||
|
||||
/*
|
||||
* try to get it off the free list first. If
|
||||
* that fails then malloc()
|
||||
*/
|
||||
pi = (ITEM *) freeListMalloc(prb->freeListPVT);
|
||||
if (!pi) {
|
||||
return S_bucket_noMemory;
|
||||
}
|
||||
|
||||
/*
|
||||
* create the hash index
|
||||
*/
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
pi->pApp = pApp;
|
||||
pi->pId = pId;
|
||||
pi->type = pBSET->type;
|
||||
assert ((hashid & ~prb->hashIdMask) == 0);
|
||||
ppi = &prb->pTable[hashid];
|
||||
/*
|
||||
* Dont reuse a resource id !
|
||||
*/
|
||||
ppiExists = (*pBSET->pCompare) (ppi, pId);
|
||||
if (ppiExists) {
|
||||
freeListFree(prb->freeListPVT,pi);
|
||||
return S_bucket_idInUse;
|
||||
}
|
||||
pi->pItem = *ppi;
|
||||
prb->pTable[hashid] = pi;
|
||||
prb->nInUse++;
|
||||
|
||||
return S_bucket_success;
|
||||
}
|
||||
|
||||
/*
|
||||
* bucketLookupAndRemoveItem ()
|
||||
*/
|
||||
static void *bucketLookupAndRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
void *pApp;
|
||||
|
||||
/*
|
||||
* create the hash index
|
||||
*/
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
assert((hashid & ~prb->hashIdMask) == 0);
|
||||
ppi = &prb->pTable[hashid];
|
||||
ppi = (*pBSET->pCompare) (ppi, pId);
|
||||
if(!ppi){
|
||||
return NULL;
|
||||
}
|
||||
prb->nInUse--;
|
||||
pi = *ppi;
|
||||
*ppi = pi->pItem;
|
||||
|
||||
pApp = (void *) pi->pApp;
|
||||
|
||||
/*
|
||||
* stuff it on the free list
|
||||
*/
|
||||
freeListFree(prb->freeListPVT, pi);
|
||||
|
||||
return pApp;
|
||||
}
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketRemoveItem()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId)?S_bucket_success:S_bucket_uknId;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketRemoveItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId)?S_bucket_success:S_bucket_uknId;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
bucketRemoveItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId)?S_bucket_success:S_bucket_uknId;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketLookupItem()
|
||||
*/
|
||||
epicsShareFunc void * epicsShareAPI
|
||||
bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
epicsShareFunc void * epicsShareAPI
|
||||
bucketLookupItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
epicsShareFunc void * epicsShareAPI
|
||||
bucketLookupItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
static void *bucketLookupItem (BUCKET *pb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
|
||||
/*
|
||||
* create the hash index
|
||||
*/
|
||||
hashid = (*pBSET->pHash) (pb, pId);
|
||||
assert((hashid & ~pb->hashIdMask) == 0);
|
||||
|
||||
/*
|
||||
* at the bottom level just
|
||||
* linear search for it.
|
||||
*/
|
||||
ppi = (*pBSET->pCompare) (&pb->pTable[hashid], pId);
|
||||
if(ppi){
|
||||
return (void *) (*ppi)->pApp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketShow()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
|
||||
{
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
unsigned nElem;
|
||||
double X;
|
||||
double XX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
unsigned count;
|
||||
unsigned maxEntries;
|
||||
|
||||
printf( " Bucket entries in use = %d bytes in use = %ld\n",
|
||||
pb->nInUse,
|
||||
(long) (sizeof(*pb)+(pb->hashIdMask+1)*
|
||||
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM)));
|
||||
|
||||
ppi = pb->pTable;
|
||||
nElem = pb->hashIdMask+1;
|
||||
X = 0.0;
|
||||
XX = 0.0;
|
||||
maxEntries = 0;
|
||||
while (ppi < &pb->pTable[nElem]) {
|
||||
pi = *ppi;
|
||||
count = 0;
|
||||
while (pi) {
|
||||
count++;
|
||||
pi = pi->pItem;
|
||||
}
|
||||
X += count;
|
||||
XX += count*count;
|
||||
if (count > maxEntries) maxEntries = count;
|
||||
ppi++;
|
||||
}
|
||||
|
||||
mean = X/nElem;
|
||||
stdDev = sqrt(XX/nElem - mean*mean);
|
||||
printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
|
||||
mean,
|
||||
stdDev,
|
||||
maxEntries);
|
||||
|
||||
return S_bucket_success;
|
||||
}
|
||||
|
||||
|
||||
91
modules/libcom/src/bucketLib/bucketLib.h
Normal file
91
modules/libcom/src/bucketLib/bucketLib.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
* hill@luke.lanl.gov
|
||||
* (505) 665 1831
|
||||
* Date: 9-93
|
||||
*
|
||||
* NOTES:
|
||||
* .01 Storage for identifier must persist until an item is deleted
|
||||
*/
|
||||
|
||||
#ifndef INCbucketLibh
|
||||
#define INCbucketLibh
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "errMdef.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
typedef unsigned BUCKETID;
|
||||
|
||||
typedef enum {bidtUnsigned, bidtPointer, bidtString} buckTypeOfId;
|
||||
|
||||
typedef struct item{
|
||||
struct item *pItem;
|
||||
const void *pId;
|
||||
const void *pApp;
|
||||
buckTypeOfId type;
|
||||
}ITEM;
|
||||
|
||||
typedef struct bucket{
|
||||
ITEM **pTable;
|
||||
void *freeListPVT;
|
||||
unsigned hashIdMask;
|
||||
unsigned hashIdNBits;
|
||||
unsigned nInUse;
|
||||
}BUCKET;
|
||||
|
||||
epicsShareFunc BUCKET * epicsShareAPI bucketCreate (unsigned nHashTableEntries);
|
||||
epicsShareFunc int epicsShareAPI bucketFree (BUCKET *prb);
|
||||
epicsShareFunc int epicsShareAPI bucketShow (BUCKET *pb);
|
||||
|
||||
/*
|
||||
* !! Identifier must exist (and remain constant) at the specified address until
|
||||
* the item is deleted from the bucket !!
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI bucketAddItemUnsignedId (BUCKET *prb,
|
||||
const unsigned *pId, const void *pApp);
|
||||
epicsShareFunc int epicsShareAPI bucketAddItemPointerId (BUCKET *prb,
|
||||
void * const *pId, const void *pApp);
|
||||
epicsShareFunc int epicsShareAPI bucketAddItemStringId (BUCKET *prb,
|
||||
const char *pId, const void *pApp);
|
||||
|
||||
epicsShareFunc int epicsShareAPI bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId);
|
||||
epicsShareFunc int epicsShareAPI bucketRemoveItemPointerId (BUCKET *prb, void * const *pId);
|
||||
epicsShareFunc int epicsShareAPI bucketRemoveItemStringId (BUCKET *prb, const char *pId);
|
||||
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId);
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupItemPointerId (BUCKET *prb, void * const *pId);
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupItemStringId (BUCKET *prb, const char *pId);
|
||||
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId);
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemPointerId (BUCKET *prb, void * const *pId);
|
||||
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemStringId (BUCKET *prb, const char *pId);
|
||||
|
||||
|
||||
/*
|
||||
* Status returned by bucketLib functions
|
||||
*/
|
||||
#define BUCKET_SUCCESS S_bucket_success
|
||||
#define S_bucket_success 0
|
||||
#define S_bucket_noMemory (M_bucket | 1) /*Memory allocation failed*/
|
||||
#define S_bucket_idInUse (M_bucket | 2) /*Identifier already in use*/
|
||||
#define S_bucket_uknId (M_bucket | 3) /*Unknown identifier*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCbucketLibh*/
|
||||
|
||||
14
modules/libcom/src/calc/Makefile
Normal file
14
modules/libcom/src/calc/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/calc
|
||||
INC += postfix.h
|
||||
Com_SRCS += postfix.c
|
||||
Com_SRCS += calcPerform.c
|
||||
|
||||
504
modules/libcom/src/calc/calcPerform.c
Normal file
504
modules/libcom/src/calc/calcPerform.c
Normal file
@@ -0,0 +1,504 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Julie Sander and Bob Dalesio
|
||||
* Date: 07-27-87
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "osiUnistd.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "errlog.h"
|
||||
#include "postfix.h"
|
||||
#include "postfixPvt.h"
|
||||
|
||||
static double calcRandom(void);
|
||||
static int cond_search(const char **ppinst, int match);
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323
|
||||
#endif
|
||||
|
||||
/* Turn off global optimization for 64-bit MSVC builds */
|
||||
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
|
||||
# pragma optimize("g", off)
|
||||
#endif
|
||||
|
||||
/* calcPerform
|
||||
*
|
||||
* Evalutate the postfix expression
|
||||
*/
|
||||
epicsShareFunc long
|
||||
calcPerform(double *parg, double *presult, const char *pinst)
|
||||
{
|
||||
double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */
|
||||
double *ptop; /* stack pointer */
|
||||
double top; /* value from top of stack */
|
||||
epicsInt32 itop; /* integer from top of stack */
|
||||
epicsUInt32 utop; /* unsigned integer from top of stack */
|
||||
int op;
|
||||
int nargs;
|
||||
|
||||
/* initialize */
|
||||
ptop = stack;
|
||||
|
||||
/* RPN evaluation loop */
|
||||
while ((op = *pinst++) != END_EXPRESSION){
|
||||
switch (op){
|
||||
|
||||
case LITERAL_DOUBLE:
|
||||
memcpy(++ptop, pinst, sizeof(double));
|
||||
pinst += sizeof(double);
|
||||
break;
|
||||
|
||||
case LITERAL_INT:
|
||||
memcpy(&itop, pinst, sizeof(epicsInt32));
|
||||
*++ptop = itop;
|
||||
pinst += sizeof(epicsInt32);
|
||||
break;
|
||||
|
||||
case FETCH_VAL:
|
||||
*++ptop = *presult;
|
||||
break;
|
||||
|
||||
case FETCH_A:
|
||||
case FETCH_B:
|
||||
case FETCH_C:
|
||||
case FETCH_D:
|
||||
case FETCH_E:
|
||||
case FETCH_F:
|
||||
case FETCH_G:
|
||||
case FETCH_H:
|
||||
case FETCH_I:
|
||||
case FETCH_J:
|
||||
case FETCH_K:
|
||||
case FETCH_L:
|
||||
*++ptop = parg[op - FETCH_A];
|
||||
break;
|
||||
|
||||
case STORE_A:
|
||||
case STORE_B:
|
||||
case STORE_C:
|
||||
case STORE_D:
|
||||
case STORE_E:
|
||||
case STORE_F:
|
||||
case STORE_G:
|
||||
case STORE_H:
|
||||
case STORE_I:
|
||||
case STORE_J:
|
||||
case STORE_K:
|
||||
case STORE_L:
|
||||
parg[op - STORE_A] = *ptop--;
|
||||
break;
|
||||
|
||||
case CONST_PI:
|
||||
*++ptop = PI;
|
||||
break;
|
||||
|
||||
case CONST_D2R:
|
||||
*++ptop = PI/180.;
|
||||
break;
|
||||
|
||||
case CONST_R2D:
|
||||
*++ptop = 180./PI;
|
||||
break;
|
||||
|
||||
case UNARY_NEG:
|
||||
*ptop = - *ptop;
|
||||
break;
|
||||
|
||||
case ADD:
|
||||
top = *ptop--;
|
||||
*ptop += top;
|
||||
break;
|
||||
|
||||
case SUB:
|
||||
top = *ptop--;
|
||||
*ptop -= top;
|
||||
break;
|
||||
|
||||
case MULT:
|
||||
top = *ptop--;
|
||||
*ptop *= top;
|
||||
break;
|
||||
|
||||
case DIV:
|
||||
top = *ptop--;
|
||||
*ptop /= top;
|
||||
break;
|
||||
|
||||
case MODULO:
|
||||
itop = (epicsInt32) *ptop--;
|
||||
if (itop)
|
||||
*ptop = (epicsInt32) *ptop % itop;
|
||||
else
|
||||
*ptop = epicsNAN;
|
||||
break;
|
||||
|
||||
case POWER:
|
||||
top = *ptop--;
|
||||
*ptop = pow(*ptop, top);
|
||||
break;
|
||||
|
||||
case ABS_VAL:
|
||||
*ptop = fabs(*ptop);
|
||||
break;
|
||||
|
||||
case EXP:
|
||||
*ptop = exp(*ptop);
|
||||
break;
|
||||
|
||||
case LOG_10:
|
||||
*ptop = log10(*ptop);
|
||||
break;
|
||||
|
||||
case LOG_E:
|
||||
*ptop = log(*ptop);
|
||||
break;
|
||||
|
||||
case MAX:
|
||||
nargs = *pinst++;
|
||||
while (--nargs) {
|
||||
top = *ptop--;
|
||||
if (*ptop < top || isnan(top))
|
||||
*ptop = top;
|
||||
}
|
||||
break;
|
||||
|
||||
case MIN:
|
||||
nargs = *pinst++;
|
||||
while (--nargs) {
|
||||
top = *ptop--;
|
||||
if (*ptop > top || isnan(top))
|
||||
*ptop = top;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQU_RT:
|
||||
*ptop = sqrt(*ptop);
|
||||
break;
|
||||
|
||||
case ACOS:
|
||||
*ptop = acos(*ptop);
|
||||
break;
|
||||
|
||||
case ASIN:
|
||||
*ptop = asin(*ptop);
|
||||
break;
|
||||
|
||||
case ATAN:
|
||||
*ptop = atan(*ptop);
|
||||
break;
|
||||
|
||||
case ATAN2:
|
||||
top = *ptop--;
|
||||
*ptop = atan2(top, *ptop); /* Ouch!: Args backwards! */
|
||||
break;
|
||||
|
||||
case COS:
|
||||
*ptop = cos(*ptop);
|
||||
break;
|
||||
|
||||
case SIN:
|
||||
*ptop = sin(*ptop);
|
||||
break;
|
||||
|
||||
case TAN:
|
||||
*ptop = tan(*ptop);
|
||||
break;
|
||||
|
||||
case COSH:
|
||||
*ptop = cosh(*ptop);
|
||||
break;
|
||||
|
||||
case SINH:
|
||||
*ptop = sinh(*ptop);
|
||||
break;
|
||||
|
||||
case TANH:
|
||||
*ptop = tanh(*ptop);
|
||||
break;
|
||||
|
||||
case CEIL:
|
||||
*ptop = ceil(*ptop);
|
||||
break;
|
||||
|
||||
case FLOOR:
|
||||
*ptop = floor(*ptop);
|
||||
break;
|
||||
|
||||
case FINITE:
|
||||
nargs = *pinst++;
|
||||
top = finite(*ptop);
|
||||
while (--nargs) {
|
||||
--ptop;
|
||||
top = top && finite(*ptop);
|
||||
}
|
||||
*ptop = top;
|
||||
break;
|
||||
|
||||
case ISINF:
|
||||
*ptop = isinf(*ptop);
|
||||
break;
|
||||
|
||||
case ISNAN:
|
||||
nargs = *pinst++;
|
||||
top = isnan(*ptop);
|
||||
while (--nargs) {
|
||||
--ptop;
|
||||
top = top || isnan(*ptop);
|
||||
}
|
||||
*ptop = top;
|
||||
break;
|
||||
|
||||
case NINT:
|
||||
top = *ptop;
|
||||
*ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
*++ptop = calcRandom();
|
||||
break;
|
||||
|
||||
case REL_OR:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop || top;
|
||||
break;
|
||||
|
||||
case REL_AND:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop && top;
|
||||
break;
|
||||
|
||||
case REL_NOT:
|
||||
*ptop = ! *ptop;
|
||||
break;
|
||||
|
||||
/* For bitwise operations on values with bit 31 set, double values
|
||||
* must first be cast to unsigned to correctly set that bit; the
|
||||
* double value must be negative in that case. The result must be
|
||||
* cast to a signed integer before converting to the double result.
|
||||
*/
|
||||
|
||||
case BIT_OR:
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
|
||||
break;
|
||||
|
||||
case BIT_EXCL_OR:
|
||||
utop = *ptop--;
|
||||
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
utop = *ptop;
|
||||
*ptop = (epicsInt32) ~utop;
|
||||
break;
|
||||
|
||||
/* The shift operators use signed integers, so a right-shift will
|
||||
* extend the sign bit into the left-hand end of the value. The
|
||||
* double-casting through unsigned here is important, see above.
|
||||
*/
|
||||
|
||||
case RIGHT_SHIFT:
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
|
||||
break;
|
||||
|
||||
case LEFT_SHIFT:
|
||||
utop = *ptop--;
|
||||
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
|
||||
break;
|
||||
|
||||
case NOT_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop != top;
|
||||
break;
|
||||
|
||||
case LESS_THAN:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop < top;
|
||||
break;
|
||||
|
||||
case LESS_OR_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop <= top;
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop == top;
|
||||
break;
|
||||
|
||||
case GR_OR_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop >= top;
|
||||
break;
|
||||
|
||||
case GR_THAN:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop > top;
|
||||
break;
|
||||
|
||||
case COND_IF:
|
||||
if (*ptop-- == 0.0 &&
|
||||
cond_search(&pinst, COND_ELSE)) return -1;
|
||||
break;
|
||||
|
||||
case COND_ELSE:
|
||||
if (cond_search(&pinst, COND_END)) return -1;
|
||||
break;
|
||||
|
||||
case COND_END:
|
||||
break;
|
||||
|
||||
default:
|
||||
errlogPrintf("calcPerform: Bad Opcode %d at %p\n", op, pinst-1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The stack should now have one item on it, the expression value */
|
||||
if (ptop != stack + 1)
|
||||
return -1;
|
||||
*presult = *ptop;
|
||||
return 0;
|
||||
}
|
||||
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
|
||||
# pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
|
||||
epicsShareFunc long
|
||||
calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores)
|
||||
{
|
||||
unsigned long inputs = 0;
|
||||
unsigned long stores = 0;
|
||||
char op;
|
||||
while ((op = *pinst++) != END_EXPRESSION) {
|
||||
switch (op) {
|
||||
|
||||
case LITERAL_DOUBLE:
|
||||
pinst += sizeof(double);
|
||||
break;
|
||||
case LITERAL_INT:
|
||||
pinst += sizeof(epicsInt32);
|
||||
break;
|
||||
case MIN:
|
||||
case MAX:
|
||||
case FINITE:
|
||||
case ISNAN:
|
||||
pinst++;
|
||||
break;
|
||||
|
||||
case FETCH_A:
|
||||
case FETCH_B:
|
||||
case FETCH_C:
|
||||
case FETCH_D:
|
||||
case FETCH_E:
|
||||
case FETCH_F:
|
||||
case FETCH_G:
|
||||
case FETCH_H:
|
||||
case FETCH_I:
|
||||
case FETCH_J:
|
||||
case FETCH_K:
|
||||
case FETCH_L:
|
||||
/* Don't claim to use an arg we already stored to */
|
||||
inputs |= (1 << (op - FETCH_A)) & ~stores;
|
||||
break;
|
||||
|
||||
case STORE_A:
|
||||
case STORE_B:
|
||||
case STORE_C:
|
||||
case STORE_D:
|
||||
case STORE_E:
|
||||
case STORE_F:
|
||||
case STORE_G:
|
||||
case STORE_H:
|
||||
case STORE_I:
|
||||
case STORE_J:
|
||||
case STORE_K:
|
||||
case STORE_L:
|
||||
stores |= (1 << (op - STORE_A));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pinputs) *pinputs = inputs;
|
||||
if (pstores) *pstores = stores;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate a random number between 0 and 1 using the algorithm
|
||||
* seed = (multy * seed) + addy Random Number Generator by Knuth
|
||||
* SemiNumerical Algorithms
|
||||
* Chapter 1
|
||||
* randy = seed / 65535.0 To normalize the number between 0 - 1
|
||||
*/
|
||||
static unsigned short seed = 0xa3bf;
|
||||
static unsigned short multy = 191 * 8 + 5; /* 191 % 8 == 5 */
|
||||
static unsigned short addy = 0x3141;
|
||||
|
||||
static double calcRandom(void)
|
||||
{
|
||||
seed = (seed * multy) + addy;
|
||||
|
||||
/* between 0 - 1 */
|
||||
return (double) seed / 65535.0;
|
||||
}
|
||||
|
||||
/* Search the instruction stream for a matching operator, skipping any
|
||||
* other conditional instructions found, and leave *ppinst pointing to
|
||||
* the next instruction to be executed.
|
||||
*/
|
||||
static int cond_search(const char **ppinst, int match)
|
||||
{
|
||||
const char *pinst = *ppinst;
|
||||
int count = 1;
|
||||
int op;
|
||||
|
||||
while ((op = *pinst++) != END_EXPRESSION) {
|
||||
if (op == match && --count == 0) {
|
||||
*ppinst = pinst;
|
||||
return 0;
|
||||
}
|
||||
switch (op) {
|
||||
case LITERAL_DOUBLE:
|
||||
pinst += sizeof(double);
|
||||
break;
|
||||
case LITERAL_INT:
|
||||
pinst += sizeof(epicsInt32);
|
||||
break;
|
||||
case MIN:
|
||||
case MAX:
|
||||
case FINITE:
|
||||
case ISNAN:
|
||||
pinst++;
|
||||
break;
|
||||
case COND_IF:
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
626
modules/libcom/src/calc/postfix.c
Normal file
626
modules/libcom/src/calc/postfix.c
Normal file
@@ -0,0 +1,626 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Subroutines used to convert an infix expression to a postfix expression
|
||||
*
|
||||
* Original Author: Bob Dalesio
|
||||
* Date: 12-12-86
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "postfix.h"
|
||||
#include "postfixPvt.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
|
||||
/* declarations for postfix */
|
||||
|
||||
/* element types */
|
||||
typedef enum {
|
||||
OPERAND,
|
||||
LITERAL_OPERAND,
|
||||
STORE_OPERATOR,
|
||||
UNARY_OPERATOR,
|
||||
VARARG_OPERATOR,
|
||||
BINARY_OPERATOR,
|
||||
SEPERATOR,
|
||||
CLOSE_PAREN,
|
||||
CONDITIONAL,
|
||||
EXPR_TERMINATOR,
|
||||
} element_type;
|
||||
|
||||
|
||||
/* element table
|
||||
*
|
||||
* structure of an element
|
||||
*/
|
||||
typedef struct expression_element{
|
||||
char *name; /* character representation of an element */
|
||||
char in_stack_pri; /* priority on translation stack */
|
||||
char in_coming_pri; /* priority in input string */
|
||||
signed char runtime_effect; /* stack change, positive means push */
|
||||
element_type type; /* element type */
|
||||
rpn_opcode code; /* postfix opcode */
|
||||
} ELEMENT;
|
||||
|
||||
/*
|
||||
* NOTE: Keep these lists sorted. Elements are searched in reverse order,
|
||||
* and where two names start with the same substring we must pick out the
|
||||
* longest name first (hence the sort requirement).
|
||||
* NOTE: All VARARG_OPERATORs have to be made known to the calcExprDump()
|
||||
* routine at the end of this file.
|
||||
*/
|
||||
static const ELEMENT operands[] = {
|
||||
/* name prio's stack element type opcode */
|
||||
{"!", 7, 8, 0, UNARY_OPERATOR, REL_NOT},
|
||||
{"(", 0, 8, 0, UNARY_OPERATOR, NOT_GENERATED},
|
||||
{"-", 7, 8, 0, UNARY_OPERATOR, UNARY_NEG},
|
||||
{".", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"0", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"0X", 0, 0, 1, LITERAL_OPERAND,LITERAL_INT},
|
||||
{"1", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"2", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"3", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"4", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"5", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"6", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"7", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"8", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"9", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"A", 0, 0, 1, OPERAND, FETCH_A},
|
||||
{"ABS", 7, 8, 0, UNARY_OPERATOR, ABS_VAL},
|
||||
{"ACOS", 7, 8, 0, UNARY_OPERATOR, ACOS},
|
||||
{"ASIN", 7, 8, 0, UNARY_OPERATOR, ASIN},
|
||||
{"ATAN", 7, 8, 0, UNARY_OPERATOR, ATAN},
|
||||
{"ATAN2", 7, 8, -1, UNARY_OPERATOR, ATAN2},
|
||||
{"B", 0, 0, 1, OPERAND, FETCH_B},
|
||||
{"C", 0, 0, 1, OPERAND, FETCH_C},
|
||||
{"CEIL", 7, 8, 0, UNARY_OPERATOR, CEIL},
|
||||
{"COS", 7, 8, 0, UNARY_OPERATOR, COS},
|
||||
{"COSH", 7, 8, 0, UNARY_OPERATOR, COSH},
|
||||
{"D", 0, 0, 1, OPERAND, FETCH_D},
|
||||
{"D2R", 0, 0, 1, OPERAND, CONST_D2R},
|
||||
{"E", 0, 0, 1, OPERAND, FETCH_E},
|
||||
{"EXP", 7, 8, 0, UNARY_OPERATOR, EXP},
|
||||
{"F", 0, 0, 1, OPERAND, FETCH_F},
|
||||
{"FINITE", 7, 8, 0, VARARG_OPERATOR,FINITE},
|
||||
{"FLOOR", 7, 8, 0, UNARY_OPERATOR, FLOOR},
|
||||
{"G", 0, 0, 1, OPERAND, FETCH_G},
|
||||
{"H", 0, 0, 1, OPERAND, FETCH_H},
|
||||
{"I", 0, 0, 1, OPERAND, FETCH_I},
|
||||
{"INF", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"ISINF", 7, 8, 0, UNARY_OPERATOR, ISINF},
|
||||
{"ISNAN", 7, 8, 0, VARARG_OPERATOR,ISNAN},
|
||||
{"J", 0, 0, 1, OPERAND, FETCH_J},
|
||||
{"K", 0, 0, 1, OPERAND, FETCH_K},
|
||||
{"L", 0, 0, 1, OPERAND, FETCH_L},
|
||||
{"LN", 7, 8, 0, UNARY_OPERATOR, LOG_E},
|
||||
{"LOG", 7, 8, 0, UNARY_OPERATOR, LOG_10},
|
||||
{"LOGE", 7, 8, 0, UNARY_OPERATOR, LOG_E},
|
||||
{"MAX", 7, 8, 0, VARARG_OPERATOR,MAX},
|
||||
{"MIN", 7, 8, 0, VARARG_OPERATOR,MIN},
|
||||
{"NINT", 7, 8, 0, UNARY_OPERATOR, NINT},
|
||||
{"NAN", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
|
||||
{"NOT", 7, 8, 0, UNARY_OPERATOR, BIT_NOT},
|
||||
{"PI", 0, 0, 1, OPERAND, CONST_PI},
|
||||
{"R2D", 0, 0, 1, OPERAND, CONST_R2D},
|
||||
{"RNDM", 0, 0, 1, OPERAND, RANDOM},
|
||||
{"SIN", 7, 8, 0, UNARY_OPERATOR, SIN},
|
||||
{"SINH", 7, 8, 0, UNARY_OPERATOR, SINH},
|
||||
{"SQR", 7, 8, 0, UNARY_OPERATOR, SQU_RT},
|
||||
{"SQRT", 7, 8, 0, UNARY_OPERATOR, SQU_RT},
|
||||
{"TAN", 7, 8, 0, UNARY_OPERATOR, TAN},
|
||||
{"TANH", 7, 8, 0, UNARY_OPERATOR, TANH},
|
||||
{"VAL", 0, 0, 1, OPERAND, FETCH_VAL},
|
||||
{"~", 7, 8, 0, UNARY_OPERATOR, BIT_NOT},
|
||||
};
|
||||
|
||||
static const ELEMENT operators[] = {
|
||||
/* name prio's stack element type opcode */
|
||||
{"!=", 3, 3, -1, BINARY_OPERATOR,NOT_EQ},
|
||||
{"#", 3, 3, -1, BINARY_OPERATOR,NOT_EQ},
|
||||
{"%", 5, 5, -1, BINARY_OPERATOR,MODULO},
|
||||
{"&", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
|
||||
{"&&", 2, 2, -1, BINARY_OPERATOR,REL_AND},
|
||||
{")", 0, 0, 0, CLOSE_PAREN, NOT_GENERATED},
|
||||
{"*", 5, 5, -1, BINARY_OPERATOR,MULT},
|
||||
{"**", 6, 6, -1, BINARY_OPERATOR,POWER},
|
||||
{"+", 4, 4, -1, BINARY_OPERATOR,ADD},
|
||||
{",", 0, 0, 0, SEPERATOR, NOT_GENERATED},
|
||||
{"-", 4, 4, -1, BINARY_OPERATOR,SUB},
|
||||
{"/", 5, 5, -1, BINARY_OPERATOR,DIV},
|
||||
{":", 0, 0, -1, CONDITIONAL, COND_ELSE},
|
||||
{":=", 0, 0, -1, STORE_OPERATOR, STORE_A},
|
||||
{";", 0, 0, 0, EXPR_TERMINATOR,NOT_GENERATED},
|
||||
{"<", 3, 3, -1, BINARY_OPERATOR,LESS_THAN},
|
||||
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT},
|
||||
{"<=", 3, 3, -1, BINARY_OPERATOR,LESS_OR_EQ},
|
||||
{"=", 3, 3, -1, BINARY_OPERATOR,EQUAL},
|
||||
{"==", 3, 3, -1, BINARY_OPERATOR,EQUAL},
|
||||
{">", 3, 3, -1, BINARY_OPERATOR,GR_THAN},
|
||||
{">=", 3, 3, -1, BINARY_OPERATOR,GR_OR_EQ},
|
||||
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT},
|
||||
{"?", 0, 0, -1, CONDITIONAL, COND_IF},
|
||||
{"AND", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
|
||||
{"OR", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
|
||||
{"XOR", 1, 1, -1, BINARY_OPERATOR,BIT_EXCL_OR},
|
||||
{"^", 6, 6, -1, BINARY_OPERATOR,POWER},
|
||||
{"|", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
|
||||
{"||", 1, 1, -1, BINARY_OPERATOR,REL_OR},
|
||||
};
|
||||
|
||||
|
||||
/* get_element
|
||||
*
|
||||
* find the next expression element in the infix expression
|
||||
*/
|
||||
static int
|
||||
get_element(int opnd, const char **ppsrc, const ELEMENT **ppel)
|
||||
{
|
||||
const ELEMENT *ptable, *pel;
|
||||
|
||||
*ppel = NULL;
|
||||
|
||||
while (isspace((int) (unsigned char) **ppsrc)) ++*ppsrc;
|
||||
if (**ppsrc == '\0') return FALSE;
|
||||
|
||||
if (opnd) {
|
||||
ptable = operands;
|
||||
pel = ptable + NELEMENTS(operands) - 1;
|
||||
} else {
|
||||
ptable = operators;
|
||||
pel = ptable + NELEMENTS(operators) - 1;
|
||||
}
|
||||
|
||||
while (pel >= ptable) {
|
||||
size_t len = strlen(pel->name);
|
||||
|
||||
if (epicsStrnCaseCmp(*ppsrc, pel->name, len) == 0) {
|
||||
*ppel = pel;
|
||||
*ppsrc += len;
|
||||
return TRUE;
|
||||
}
|
||||
--pel;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* postfix
|
||||
*
|
||||
* convert an infix expression to a postfix expression
|
||||
*/
|
||||
epicsShareFunc long
|
||||
postfix(const char *psrc, char *pout, short *perror)
|
||||
{
|
||||
ELEMENT stack[80];
|
||||
ELEMENT *pstacktop = stack;
|
||||
const ELEMENT *pel;
|
||||
int operand_needed = TRUE;
|
||||
int runtime_depth = 0;
|
||||
int cond_count = 0;
|
||||
char * const pdest = pout;
|
||||
char *pnext;
|
||||
|
||||
if (psrc == NULL || *psrc == '\0' ||
|
||||
pout == NULL || perror == NULL) {
|
||||
if (perror) *perror = CALC_ERR_NULL_ARG;
|
||||
if (pout) *pout = END_EXPRESSION;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* place the expression elements into postfix */
|
||||
*pout = END_EXPRESSION;
|
||||
*perror = CALC_ERR_NONE;
|
||||
|
||||
while (get_element(operand_needed, &psrc, &pel)) {
|
||||
switch (pel->type) {
|
||||
|
||||
case OPERAND:
|
||||
*pout++ = pel->code;
|
||||
runtime_depth += pel->runtime_effect;
|
||||
operand_needed = FALSE;
|
||||
break;
|
||||
|
||||
case LITERAL_OPERAND:
|
||||
runtime_depth += pel->runtime_effect;
|
||||
|
||||
psrc -= strlen(pel->name);
|
||||
if (pel->code == LITERAL_DOUBLE) {
|
||||
double lit_d;
|
||||
epicsInt32 lit_i;
|
||||
|
||||
if (epicsParseDouble(psrc, &lit_d, &pnext)) {
|
||||
*perror = CALC_ERR_BAD_LITERAL;
|
||||
goto bad;
|
||||
}
|
||||
psrc = pnext;
|
||||
lit_i = (epicsInt32) lit_d;
|
||||
if (lit_d != (double) lit_i) {
|
||||
*pout++ = pel->code;
|
||||
memcpy(pout, &lit_d, sizeof(double));
|
||||
pout += sizeof(double);
|
||||
} else {
|
||||
*pout++ = LITERAL_INT;
|
||||
memcpy(pout, &lit_i, sizeof(epicsInt32));
|
||||
pout += sizeof(epicsInt32);
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsUInt32 lit_ui;
|
||||
|
||||
assert(pel->code == LITERAL_INT);
|
||||
if (epicsParseUInt32(psrc, &lit_ui, 0, &pnext)) {
|
||||
*perror = CALC_ERR_BAD_LITERAL;
|
||||
goto bad;
|
||||
}
|
||||
psrc = pnext;
|
||||
*pout++ = LITERAL_INT;
|
||||
memcpy(pout, &lit_ui, sizeof(epicsUInt32));
|
||||
pout += sizeof(epicsUInt32);
|
||||
}
|
||||
|
||||
operand_needed = FALSE;
|
||||
break;
|
||||
|
||||
case STORE_OPERATOR:
|
||||
if (pout == pdest || pstacktop > stack ||
|
||||
*--pout < FETCH_A || *pout > FETCH_L) {
|
||||
*perror = CALC_ERR_BAD_ASSIGNMENT;
|
||||
goto bad;
|
||||
}
|
||||
/* Convert fetch into a store on the stack */
|
||||
*++pstacktop = *pel;
|
||||
pstacktop->code = STORE_A + *pout - FETCH_A;
|
||||
runtime_depth -= 1;
|
||||
operand_needed = TRUE;
|
||||
break;
|
||||
|
||||
case UNARY_OPERATOR:
|
||||
case VARARG_OPERATOR:
|
||||
/* Move operators of >= priority to the output */
|
||||
while ((pstacktop > stack) &&
|
||||
(pstacktop->in_stack_pri >= pel->in_coming_pri)) {
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
|
||||
/* Push new operator onto stack */
|
||||
pstacktop++;
|
||||
*pstacktop = *pel;
|
||||
break;
|
||||
|
||||
case BINARY_OPERATOR:
|
||||
/* Move operators of >= priority to the output */
|
||||
while ((pstacktop > stack) &&
|
||||
(pstacktop->in_stack_pri >= pel->in_coming_pri)) {
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
|
||||
/* Push new operator onto stack */
|
||||
pstacktop++;
|
||||
*pstacktop = *pel;
|
||||
|
||||
operand_needed = TRUE;
|
||||
break;
|
||||
|
||||
case SEPERATOR:
|
||||
/* Move operators to the output until open paren */
|
||||
while (pstacktop->name[0] != '(') {
|
||||
if (pstacktop <= stack+1) {
|
||||
*perror = CALC_ERR_BAD_SEPERATOR;
|
||||
goto bad;
|
||||
}
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
operand_needed = TRUE;
|
||||
pstacktop->runtime_effect -= 1;
|
||||
break;
|
||||
|
||||
case CLOSE_PAREN:
|
||||
/* Move operators to the output until matching paren */
|
||||
while (pstacktop->name[0] != '(') {
|
||||
if (pstacktop <= stack+1) {
|
||||
*perror = CALC_ERR_PAREN_NOT_OPEN;
|
||||
goto bad;
|
||||
}
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
pstacktop--; /* remove ( from stack */
|
||||
/* if there is a vararg operator before the opening paren,
|
||||
it inherits the (opening) paren's stack effect */
|
||||
if ((pstacktop > stack) &&
|
||||
pstacktop->type == VARARG_OPERATOR) {
|
||||
pstacktop->runtime_effect = (pstacktop+1)->runtime_effect;
|
||||
/* check for no arguments */
|
||||
if (pstacktop->runtime_effect > 0) {
|
||||
*perror = CALC_ERR_INCOMPLETE;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CONDITIONAL:
|
||||
/* Move operators of > priority to the output */
|
||||
while ((pstacktop > stack) &&
|
||||
(pstacktop->in_stack_pri > pel->in_coming_pri)) {
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
|
||||
/* Add new element to the output */
|
||||
*pout++ = pel->code;
|
||||
runtime_depth += pel->runtime_effect;
|
||||
|
||||
/* For : operator, also push COND_END code to stack */
|
||||
if (pel->name[0] == ':') {
|
||||
if (--cond_count < 0) {
|
||||
*perror = CALC_ERR_CONDITIONAL;
|
||||
goto bad;
|
||||
}
|
||||
pstacktop++;
|
||||
*pstacktop = *pel;
|
||||
pstacktop->code = COND_END;
|
||||
pstacktop->runtime_effect = 0;
|
||||
} else {
|
||||
cond_count++;
|
||||
}
|
||||
|
||||
operand_needed = TRUE;
|
||||
break;
|
||||
|
||||
case EXPR_TERMINATOR:
|
||||
/* Move everything from stack to the output */
|
||||
while (pstacktop > stack) {
|
||||
if (pstacktop->name[0] == '(') {
|
||||
*perror = CALC_ERR_PAREN_OPEN;
|
||||
goto bad;
|
||||
}
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
|
||||
if (cond_count != 0) {
|
||||
*perror = CALC_ERR_CONDITIONAL;
|
||||
goto bad;
|
||||
}
|
||||
if (runtime_depth > 1) {
|
||||
*perror = CALC_ERR_TOOMANY;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
operand_needed = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
*perror = CALC_ERR_INTERNAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (runtime_depth < 0) {
|
||||
*perror = CALC_ERR_UNDERFLOW;
|
||||
goto bad;
|
||||
}
|
||||
if (runtime_depth >= CALCPERFORM_STACK) {
|
||||
*perror = CALC_ERR_OVERFLOW;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (*psrc != '\0') {
|
||||
*perror = CALC_ERR_SYNTAX;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Move everything from stack to the output */
|
||||
while (pstacktop > stack) {
|
||||
if (pstacktop->name[0] == '(') {
|
||||
*perror = CALC_ERR_PAREN_OPEN;
|
||||
goto bad;
|
||||
}
|
||||
*pout++ = pstacktop->code;
|
||||
if (pstacktop->type == VARARG_OPERATOR) {
|
||||
*pout++ = 1 - pstacktop->runtime_effect;
|
||||
}
|
||||
runtime_depth += pstacktop->runtime_effect;
|
||||
pstacktop--;
|
||||
}
|
||||
*pout = END_EXPRESSION;
|
||||
|
||||
if (cond_count != 0) {
|
||||
*perror = CALC_ERR_CONDITIONAL;
|
||||
goto bad;
|
||||
}
|
||||
if (operand_needed || runtime_depth != 1) {
|
||||
*perror = CALC_ERR_INCOMPLETE;
|
||||
goto bad;
|
||||
}
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
*pdest = END_EXPRESSION;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* calcErrorStr
|
||||
*
|
||||
* Return a message string appropriate for the given error code
|
||||
*/
|
||||
epicsShareFunc const char *
|
||||
calcErrorStr(short error)
|
||||
{
|
||||
static const char *errStrs[] = {
|
||||
"No error",
|
||||
"Too many results returned",
|
||||
"Badly formed numeric literal",
|
||||
"Bad assignment target",
|
||||
"Comma without enclosing parentheses",
|
||||
"Close parenthesis found without open",
|
||||
"Parenthesis still open at end of expression",
|
||||
"Unbalanced conditional ?: operators",
|
||||
"Incomplete expression, operand missing",
|
||||
"Not enough operands provided",
|
||||
"Runtime stack overflow",
|
||||
"Syntax error, unknown operator/operand",
|
||||
"NULL or empty input argument to postfix()",
|
||||
"Internal error, unknown element type",
|
||||
};
|
||||
|
||||
if (error < CALC_ERR_NONE || error > CALC_ERR_INTERNAL)
|
||||
return NULL;
|
||||
return errStrs[error];
|
||||
}
|
||||
|
||||
|
||||
/* calcExprDump
|
||||
*
|
||||
* Disassemble the given postfix instructions to stdout
|
||||
*/
|
||||
epicsShareFunc void
|
||||
calcExprDump(const char *pinst)
|
||||
{
|
||||
static const char *opcodes[] = {
|
||||
"End Expression",
|
||||
/* Operands */
|
||||
"LITERAL_DOUBLE", "LITERAL_INT", "VAL",
|
||||
"FETCH_A", "FETCH_B", "FETCH_C", "FETCH_D", "FETCH_E", "FETCH_F",
|
||||
"FETCH_G", "FETCH_H", "FETCH_I", "FETCH_J", "FETCH_K", "FETCH_L",
|
||||
/* Assignment */
|
||||
"STORE_A", "STORE_B", "STORE_C", "STORE_D", "STORE_E", "STORE_F",
|
||||
"STORE_G", "STORE_H", "STORE_I", "STORE_J", "STORE_K", "STORE_L",
|
||||
/* Trigonometry Constants */
|
||||
"CONST_PI",
|
||||
"CONST_D2R",
|
||||
"CONST_R2D",
|
||||
/* Arithmetic */
|
||||
"UNARY_NEG",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"MULT",
|
||||
"DIV",
|
||||
"MODULO",
|
||||
"POWER",
|
||||
/* Algebraic */
|
||||
"ABS_VAL",
|
||||
"EXP",
|
||||
"LOG_10",
|
||||
"LOG_E",
|
||||
"MAX",
|
||||
"MIN",
|
||||
"SQU_RT",
|
||||
/* Trigonometric */
|
||||
"ACOS",
|
||||
"ASIN",
|
||||
"ATAN",
|
||||
"ATAN2",
|
||||
"COS",
|
||||
"COSH",
|
||||
"SIN",
|
||||
"SINH",
|
||||
"TAN",
|
||||
"TANH",
|
||||
/* Numeric */
|
||||
"CEIL",
|
||||
"FLOOR",
|
||||
"FINITE",
|
||||
"ISINF",
|
||||
"ISNAN",
|
||||
"NINT",
|
||||
"RANDOM",
|
||||
/* Boolean */
|
||||
"REL_OR",
|
||||
"REL_AND",
|
||||
"REL_NOT",
|
||||
/* Bitwise */
|
||||
"BIT_OR",
|
||||
"BIT_AND",
|
||||
"BIT_EXCL_OR",
|
||||
"BIT_NOT",
|
||||
"RIGHT_SHIFT",
|
||||
"LEFT_SHIFT",
|
||||
/* Relationals */
|
||||
"NOT_EQ",
|
||||
"LESS_THAN",
|
||||
"LESS_OR_EQ",
|
||||
"EQUAL",
|
||||
"GR_OR_EQ",
|
||||
"GR_THAN",
|
||||
/* Conditional */
|
||||
"COND_IF",
|
||||
"COND_ELSE",
|
||||
"COND_END",
|
||||
/* Misc */
|
||||
"NOT_GENERATED"
|
||||
};
|
||||
char op;
|
||||
double lit_d;
|
||||
epicsInt32 lit_i;
|
||||
|
||||
while ((op = *pinst) != END_EXPRESSION) {
|
||||
switch (op) {
|
||||
case LITERAL_DOUBLE:
|
||||
memcpy(&lit_d, ++pinst, sizeof(double));
|
||||
printf("\tDouble %g\n", lit_d);
|
||||
pinst += sizeof(double);
|
||||
break;
|
||||
case LITERAL_INT:
|
||||
memcpy(&lit_i, ++pinst, sizeof(epicsInt32));
|
||||
printf("\tInteger %d (0x%x)\n", lit_i, lit_i);
|
||||
pinst += sizeof(epicsInt32);
|
||||
break;
|
||||
case MIN:
|
||||
case MAX:
|
||||
case FINITE:
|
||||
case ISNAN:
|
||||
printf("\t%s, %d arg(s)\n", opcodes[(int) op], *++pinst);
|
||||
pinst++;
|
||||
break;
|
||||
default:
|
||||
printf("\t%s\n", opcodes[(int) op]);
|
||||
pinst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
modules/libcom/src/calc/postfix.h
Normal file
89
modules/libcom/src/calc/postfix.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* postfix.h
|
||||
* Original Author: Bob Dalesio
|
||||
* Date: 9-21-88
|
||||
*/
|
||||
|
||||
#ifndef INCpostfixh
|
||||
#define INCpostfixh
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#define CALCPERFORM_NARGS 12
|
||||
#define CALCPERFORM_STACK 80
|
||||
|
||||
#define INFIX_TO_POSTFIX_SIZE(n) ((n)*21/6)
|
||||
/* The above expression is an estimate of the maximum postfix buffer
|
||||
* size needed for a given infix expression buffer (the argument must count
|
||||
* the trailing nil byte in the input expression string). The actual size
|
||||
* needed is never larger than this value, although it is actually a
|
||||
* few bytes smaller for some sizes.
|
||||
*
|
||||
* The maximum expansion from infix to postfix is for the sub-expression
|
||||
* .1?.1:
|
||||
* which is 6 characters long and results in 21 bytes of postfix:
|
||||
* .1 => LITERAL_DOUBLE + 8 byte value
|
||||
* ? => COND_IF
|
||||
* .1 => LITERAL_DOUBLE + 8 byte value
|
||||
* : => COND_ELSE
|
||||
* ...
|
||||
* => COND_END
|
||||
* For other short expressions the factor 21/6 always gives a big enough
|
||||
* postfix buffer (proven by hand, look at '1+' and '.1+' as well).
|
||||
*/
|
||||
|
||||
/* These are not hard limits, just default sizes for the database */
|
||||
#define MAX_INFIX_SIZE 100
|
||||
#define MAX_POSTFIX_SIZE INFIX_TO_POSTFIX_SIZE(MAX_INFIX_SIZE)
|
||||
|
||||
|
||||
/* Error numbers from postfix */
|
||||
|
||||
#define CALC_ERR_NONE 0 /* No error */
|
||||
#define CALC_ERR_TOOMANY 1 /* Too many results returned */
|
||||
#define CALC_ERR_BAD_LITERAL 2 /* Bad numeric literal */
|
||||
#define CALC_ERR_BAD_ASSIGNMENT 3 /* Bad assignment target */
|
||||
#define CALC_ERR_BAD_SEPERATOR 4 /* Comma without parentheses */
|
||||
#define CALC_ERR_PAREN_NOT_OPEN 5 /* Close parenthesis without open */
|
||||
#define CALC_ERR_PAREN_OPEN 6 /* Open parenthesis at end of expression */
|
||||
#define CALC_ERR_CONDITIONAL 7 /* Unbalanced conditional ?: operators */
|
||||
#define CALC_ERR_INCOMPLETE 8 /* Incomplete expression, operand missing */
|
||||
#define CALC_ERR_UNDERFLOW 9 /* Runtime stack would underflow */
|
||||
#define CALC_ERR_OVERFLOW 10 /* Runtime stack would overflow */
|
||||
#define CALC_ERR_SYNTAX 11 /* Syntax error */
|
||||
#define CALC_ERR_NULL_ARG 12 /* NULL or empty input argument */
|
||||
#define CALC_ERR_INTERNAL 13 /* Internal error, bad element type */
|
||||
/* Changes in the above errors must also be made in calcErrorStr() */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc long
|
||||
postfix(const char *pinfix, char *ppostfix, short *perror);
|
||||
|
||||
epicsShareFunc long
|
||||
calcPerform(double *parg, double *presult, const char *ppostfix);
|
||||
|
||||
epicsShareFunc long
|
||||
calcArgUsage(const char *ppostfix, unsigned long *pinputs, unsigned long *pstores);
|
||||
|
||||
epicsShareFunc const char *
|
||||
calcErrorStr(short error);
|
||||
|
||||
epicsShareFunc void
|
||||
calcExprDump(const char *pinst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INCpostfixh */
|
||||
104
modules/libcom/src/calc/postfixPvt.h
Normal file
104
modules/libcom/src/calc/postfixPvt.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* postfixPvt.h
|
||||
* Original Author: Bob Dalesio
|
||||
* Date: 9-21-88
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* 1. The FETCH_A through FETCH_L and STORE_A through STORE_L opcodes must
|
||||
* be contiguous.
|
||||
* 2. The LITERAL opcodes are followed by a binary representation of their
|
||||
* values, but these are not aligned properly.
|
||||
* 3. The var-arg functions MIN, MAX, FINITE and ISNAN are followed by
|
||||
* a byte giving the number of arguments to process.
|
||||
* 4. You can't use strlen() on an RPN buffer since the literal values
|
||||
* can contain zero bytes.
|
||||
*/
|
||||
|
||||
#ifndef INCpostfixPvth
|
||||
#define INCpostfixPvth
|
||||
|
||||
|
||||
/* RPN opcodes */
|
||||
typedef enum {
|
||||
END_EXPRESSION = 0,
|
||||
/* Operands */
|
||||
LITERAL_DOUBLE, LITERAL_INT, FETCH_VAL,
|
||||
FETCH_A, FETCH_B, FETCH_C, FETCH_D, FETCH_E, FETCH_F,
|
||||
FETCH_G, FETCH_H, FETCH_I, FETCH_J, FETCH_K, FETCH_L,
|
||||
/* Assignment */
|
||||
STORE_A, STORE_B, STORE_C, STORE_D, STORE_E, STORE_F,
|
||||
STORE_G, STORE_H, STORE_I, STORE_J, STORE_K, STORE_L,
|
||||
/* Trigonometry Constants */
|
||||
CONST_PI,
|
||||
CONST_D2R,
|
||||
CONST_R2D,
|
||||
/* Arithmetic */
|
||||
UNARY_NEG,
|
||||
ADD,
|
||||
SUB,
|
||||
MULT,
|
||||
DIV,
|
||||
MODULO,
|
||||
POWER,
|
||||
/* Algebraic */
|
||||
ABS_VAL,
|
||||
EXP,
|
||||
LOG_10,
|
||||
LOG_E,
|
||||
MAX,
|
||||
MIN,
|
||||
SQU_RT,
|
||||
/* Trigonometric */
|
||||
ACOS,
|
||||
ASIN,
|
||||
ATAN,
|
||||
ATAN2,
|
||||
COS,
|
||||
COSH,
|
||||
SIN,
|
||||
SINH,
|
||||
TAN,
|
||||
TANH,
|
||||
/* Numeric */
|
||||
CEIL,
|
||||
FLOOR,
|
||||
FINITE,
|
||||
ISINF,
|
||||
ISNAN,
|
||||
NINT,
|
||||
RANDOM,
|
||||
/* Boolean */
|
||||
REL_OR,
|
||||
REL_AND,
|
||||
REL_NOT,
|
||||
/* Bitwise */
|
||||
BIT_OR,
|
||||
BIT_AND,
|
||||
BIT_EXCL_OR,
|
||||
BIT_NOT,
|
||||
RIGHT_SHIFT,
|
||||
LEFT_SHIFT,
|
||||
/* Relationals */
|
||||
NOT_EQ,
|
||||
LESS_THAN,
|
||||
LESS_OR_EQ,
|
||||
EQUAL,
|
||||
GR_OR_EQ,
|
||||
GR_THAN,
|
||||
/* Conditional */
|
||||
COND_IF,
|
||||
COND_ELSE,
|
||||
COND_END,
|
||||
/* Misc */
|
||||
NOT_GENERATED
|
||||
} rpn_opcode;
|
||||
|
||||
#endif /* INCpostfixPvth */
|
||||
13
modules/libcom/src/cppStd/Makefile
Normal file
13
modules/libcom/src/cppStd/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/cppStd
|
||||
INC += epicsAlgorithm.h
|
||||
INC += epicsExcept.h
|
||||
|
||||
79
modules/libcom/src/cppStd/epicsAlgorithm.h
Normal file
79
modules/libcom/src/cppStd/epicsAlgorithm.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
// epicsAlgorithm.h
|
||||
// Authors: Jeff Hill & Andrew Johnson
|
||||
|
||||
#ifndef __EPICS_ALGORITHM_H__
|
||||
#define __EPICS_ALGORITHM_H__
|
||||
|
||||
#include "epicsMath.h"
|
||||
|
||||
// The C++ standard only requires types to be less-than comparable, so
|
||||
// the epicsMin and epicsMax templates only use operator <
|
||||
|
||||
// epicsMin
|
||||
|
||||
template <class T>
|
||||
inline const T& epicsMin (const T& a, const T& b)
|
||||
{
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
// If b is a NaN the above template returns a, but should return NaN.
|
||||
// These specializations ensure that epicsMin(x,NaN) == NaN
|
||||
|
||||
template <>
|
||||
inline const float& epicsMin (const float& a, const float& b)
|
||||
{
|
||||
return (b < a) || isnan(b) ? b : a;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const double& epicsMin (const double& a, const double& b)
|
||||
{
|
||||
return (b < a) || isnan(b) ? b : a;
|
||||
}
|
||||
|
||||
|
||||
// epicsMax
|
||||
|
||||
template <class T>
|
||||
inline const T& epicsMax (const T& a, const T& b)
|
||||
{
|
||||
return (a < b) ? b : a;
|
||||
}
|
||||
|
||||
// If b is a NaN the above template returns a, but should return NaN.
|
||||
// These specializations ensure that epicsMax(x,NaN) == NaN
|
||||
|
||||
template <>
|
||||
inline const float& epicsMax (const float& a, const float& b)
|
||||
{
|
||||
return (a < b) || isnan(b) ? b : a;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const double& epicsMax (const double& a, const double& b)
|
||||
{
|
||||
return (a < b) || isnan(b) ? b : a;
|
||||
}
|
||||
|
||||
|
||||
// epicsSwap
|
||||
|
||||
template <class T>
|
||||
inline void epicsSwap(T& a, T& b)
|
||||
{
|
||||
T temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
#endif // __EPICS_ALGORITHM_H__
|
||||
71
modules/libcom/src/cppStd/epicsExcept.h
Normal file
71
modules/libcom/src/cppStd/epicsExcept.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
// Author: Andrew Johnson & Jeff Hill
|
||||
// Date: December 2000
|
||||
|
||||
#ifndef __EPICS_EXCEPT_H__
|
||||
#define __EPICS_EXCEPT_H__
|
||||
|
||||
#define epicsThrowHere(exc) \
|
||||
throw locationException(exc, __FILE__, __LINE__)
|
||||
|
||||
class sourceLocation {
|
||||
public: // Functions
|
||||
sourceLocation(const char *fileName, int lineNumber);
|
||||
// sourceLocation(const sourceLocation&); Copy constructable
|
||||
// sourceLocation& operator=(const sourceLocation&); Assignable
|
||||
|
||||
const char *fileName() const;
|
||||
int lineNumber() const;
|
||||
|
||||
private: // Hide compiler-generated member functions
|
||||
sourceLocation(); // default constructor
|
||||
|
||||
private: // Data
|
||||
const char *file;
|
||||
int line;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class locationException : public T, public sourceLocation {
|
||||
public:
|
||||
locationException(const T& exc, const char *fileName, int lineNumber);
|
||||
};
|
||||
|
||||
|
||||
/* Example:
|
||||
* if (status) epicsThrowHere(std::logic_error("operation failed!"));
|
||||
* try { ... } catch(sourceLocation& where) { ... }
|
||||
*/
|
||||
|
||||
// END OF DECLARATIONS
|
||||
|
||||
// INLINE FUNCTIONS
|
||||
|
||||
// sourceFileLocation
|
||||
inline sourceLocation::sourceLocation (const char *fileName, int lineNumber) :
|
||||
file(fileName), line(lineNumber) {}
|
||||
|
||||
inline const char* sourceLocation::fileName () const {
|
||||
return this->file;
|
||||
}
|
||||
|
||||
inline int sourceLocation::lineNumber () const {
|
||||
return this->line;
|
||||
}
|
||||
|
||||
// locationException<T>
|
||||
template <class T>
|
||||
inline locationException<T>::locationException
|
||||
(const char *fileName, int lineNumber, const E& exc) :
|
||||
T(exc), sourceLocation(fileName, lineNumber) {}
|
||||
|
||||
|
||||
#endif // __EPICS_EXCEPT_H__
|
||||
13
modules/libcom/src/cvtFast/Makefile
Normal file
13
modules/libcom/src/cvtFast/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/cvtFast
|
||||
INC += cvtFast.h
|
||||
Com_SRCS += cvtFast.c
|
||||
|
||||
523
modules/libcom/src/cvtFast/cvtFast.c
Normal file
523
modules/libcom/src/cvtFast/cvtFast.c
Normal file
@@ -0,0 +1,523 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* Fast numeric to string conversions
|
||||
*
|
||||
* Original Authors:
|
||||
* Bob Dalesio, Mark Anderson and Marty Kraimer
|
||||
* Date: 12 January 1993
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cvtFast.h"
|
||||
#include "epicsMath.h"
|
||||
#include "epicsStdio.h"
|
||||
|
||||
/*
|
||||
* These routines convert numbers up to +/- 10,000,000.
|
||||
* They defer to sprintf() for numbers requiring more than
|
||||
* 8 places of precision.
|
||||
*/
|
||||
static epicsInt32 frac_multiplier[] =
|
||||
{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
|
||||
|
||||
int cvtFloatToString(float flt_value, char *pdest,
|
||||
epicsUInt16 precision)
|
||||
{
|
||||
int got_one, i;
|
||||
epicsInt32 whole, iplace, number, fraction, fplace;
|
||||
float ftemp;
|
||||
char *startAddr;
|
||||
|
||||
/* can this routine handle this conversion */
|
||||
if (isnan(flt_value) || precision > 8 ||
|
||||
flt_value > 10000000.0 || flt_value < -10000000.0) {
|
||||
if (precision > 8 || flt_value >= 1e8 || flt_value <= -1e8) {
|
||||
if (precision > 12) precision = 12; /* FIXME */
|
||||
sprintf(pdest, "%*.*e", precision+6, precision, (double) flt_value);
|
||||
} else {
|
||||
if (precision > 3) precision = 3; /* FIXME */
|
||||
sprintf(pdest, "%.*f", precision, (double) flt_value);
|
||||
}
|
||||
return((int)strlen(pdest));
|
||||
}
|
||||
startAddr = pdest;
|
||||
|
||||
/* determine the sign */
|
||||
if (flt_value < 0){
|
||||
*pdest++ = '-';
|
||||
flt_value = -flt_value;
|
||||
};
|
||||
|
||||
/* remove the whole number portion */
|
||||
whole = (epicsInt32)flt_value;
|
||||
ftemp = flt_value - whole;
|
||||
|
||||
/* multiplier to convert fractional portion to integer */
|
||||
fplace = frac_multiplier[precision];
|
||||
fraction = (epicsInt32)(ftemp * fplace * 10);
|
||||
fraction = (fraction + 5) / 10; /* round up */
|
||||
|
||||
/* determine rounding into the whole number portion */
|
||||
if ((fraction / fplace) >= 1){
|
||||
whole++;
|
||||
fraction -= fplace;
|
||||
}
|
||||
|
||||
/* whole numbers */
|
||||
got_one = 0;
|
||||
for (iplace = 10000000; iplace >= 1; iplace /= 10){
|
||||
if (whole >= iplace){
|
||||
got_one = 1;
|
||||
number = whole / iplace;
|
||||
whole = whole - (number * iplace);
|
||||
*pdest = number + '0';
|
||||
pdest++;
|
||||
}else if (got_one){
|
||||
*pdest = '0';
|
||||
pdest++;
|
||||
}
|
||||
}
|
||||
if (!got_one){
|
||||
*pdest = '0';
|
||||
pdest++;
|
||||
}
|
||||
|
||||
/* fraction */
|
||||
if (precision > 0){
|
||||
/* convert fractional portional to ASCII */
|
||||
*pdest = '.';
|
||||
pdest++;
|
||||
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
|
||||
number = fraction / fplace;
|
||||
fraction -= number * fplace;
|
||||
*pdest = number + '0';
|
||||
pdest++;
|
||||
}
|
||||
}
|
||||
*pdest = 0;
|
||||
|
||||
return((int)(pdest - startAddr));
|
||||
}
|
||||
|
||||
int cvtDoubleToString(
|
||||
double flt_value,
|
||||
char *pdest,
|
||||
epicsUInt16 precision)
|
||||
{
|
||||
epicsUInt16 got_one,i;
|
||||
epicsInt32 whole,iplace,number,fraction,fplace;
|
||||
double ftemp;
|
||||
char *startAddr;
|
||||
|
||||
/* can this routine handle this conversion */
|
||||
if (isnan(flt_value) || precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) {
|
||||
if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) {
|
||||
if(precision>17) precision=17;
|
||||
sprintf(pdest,"%*.*e",precision+7,precision,
|
||||
flt_value);
|
||||
} else {
|
||||
if(precision>3) precision=3;
|
||||
sprintf(pdest,"%.*f",precision,flt_value);
|
||||
}
|
||||
return((int)strlen(pdest));
|
||||
}
|
||||
startAddr = pdest;
|
||||
|
||||
/* determine the sign */
|
||||
if (flt_value < 0){
|
||||
*pdest++ = '-';
|
||||
flt_value = -flt_value;
|
||||
};
|
||||
|
||||
/* remove the whole number portion */
|
||||
whole = (epicsInt32)flt_value;
|
||||
ftemp = flt_value - whole;
|
||||
|
||||
/* multiplier to convert fractional portion to integer */
|
||||
fplace = frac_multiplier[precision];
|
||||
fraction = (epicsInt32)(ftemp * fplace * 10);
|
||||
fraction = (fraction + 5) / 10; /* round up */
|
||||
|
||||
/* determine rounding into the whole number portion */
|
||||
if ((fraction / fplace) >= 1){
|
||||
whole++;
|
||||
fraction -= fplace;
|
||||
}
|
||||
|
||||
/* whole numbers */
|
||||
got_one = 0;
|
||||
for (iplace = 10000000; iplace >= 1; iplace /= 10){
|
||||
if (whole >= iplace){
|
||||
got_one = 1;
|
||||
number = whole / iplace;
|
||||
whole = whole - (number * iplace);
|
||||
*pdest = number + '0';
|
||||
pdest++;
|
||||
}else if (got_one){
|
||||
*pdest = '0';
|
||||
pdest++;
|
||||
}
|
||||
}
|
||||
if (!got_one){
|
||||
*pdest = '0';
|
||||
pdest++;
|
||||
}
|
||||
|
||||
/* fraction */
|
||||
if (precision > 0){
|
||||
/* convert fractional portional to ASCII */
|
||||
*pdest = '.';
|
||||
pdest++;
|
||||
for (fplace /= 10, i = precision; i > 0; fplace /= 10,i--){
|
||||
number = fraction / fplace;
|
||||
fraction -= number * fplace;
|
||||
*pdest = number + '0';
|
||||
pdest++;
|
||||
}
|
||||
}
|
||||
*pdest = 0;
|
||||
|
||||
return((int)(pdest - startAddr));
|
||||
}
|
||||
|
||||
/*
|
||||
* These routines are provided for backwards compatibility,
|
||||
* extensions such as MEDM, edm and histtool use them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cvtFloatToExpString
|
||||
*
|
||||
* Converts a float to a %e formatted string
|
||||
*/
|
||||
int cvtFloatToExpString(float val, char *pdest, epicsUInt16 precision)
|
||||
{
|
||||
return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* cvtFloatToCompactString
|
||||
*
|
||||
* Converts a float to a %g formatted string.
|
||||
* The result uses %f notation for 10e-4 < |value| < 10e+4,
|
||||
* otherwise %e notation.
|
||||
*/
|
||||
int cvtFloatToCompactString(float val, char *pdest, epicsUInt16 precision)
|
||||
{
|
||||
if ((val < 1.e4 && val > 1.e-4) ||
|
||||
(val > -1.e4 && val < -1.e-4) ||
|
||||
val == 0.0)
|
||||
return cvtFloatToString(val, pdest, precision);
|
||||
|
||||
return cvtFloatToExpString(val, pdest, precision);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* cvtDoubleToExpString
|
||||
*
|
||||
* Converts a double to a %e formatted string
|
||||
*/
|
||||
|
||||
int cvtDoubleToExpString(double val, char *pdest, epicsUInt16 precision)
|
||||
{
|
||||
return epicsSnprintf(pdest, MAX_STRING_SIZE, "%.*e", precision, val);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* cvtDoubleToCompactString
|
||||
*
|
||||
* Converts a double to %g formatted string.
|
||||
* The result uses %f notation for 10e-4 < |value| < 10e+4,
|
||||
* otherwise %e notation.
|
||||
*/
|
||||
int cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 precision)
|
||||
{
|
||||
if ((val < 1.e4 && val > 1.e-4) ||
|
||||
(val > -1.e4 && val < -1.e-4) ||
|
||||
val == 0.0)
|
||||
return cvtDoubleToString(val, pdest, precision);
|
||||
|
||||
return cvtDoubleToExpString(val, pdest, precision);
|
||||
}
|
||||
|
||||
|
||||
/* Integer conversion primitives */
|
||||
|
||||
static size_t
|
||||
UInt32ToDec(epicsUInt32 val, char *pdest)
|
||||
{
|
||||
int i;
|
||||
char digit[10];
|
||||
size_t len;
|
||||
|
||||
for (i = 0; val; i++) {
|
||||
epicsUInt32 tenth = val / 10;
|
||||
|
||||
digit[i] = val - tenth * 10 + '0';
|
||||
val = tenth;
|
||||
}
|
||||
len = i;
|
||||
|
||||
while (i > 0)
|
||||
*pdest++ = digit[--i];
|
||||
|
||||
*pdest = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UInt32ToBase(epicsUInt32 val, char *pdest, int base)
|
||||
{
|
||||
int i;
|
||||
char digit, digits[32];
|
||||
size_t len;
|
||||
|
||||
for (i = 0; val; i++) {
|
||||
epicsUInt32 tenth = val / base;
|
||||
|
||||
digit = val - tenth * base;
|
||||
digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
|
||||
val = tenth;
|
||||
}
|
||||
len = i;
|
||||
|
||||
while (i > 0)
|
||||
*pdest++ = digits[--i];
|
||||
|
||||
*pdest = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UInt64ToDec(epicsUInt64 val, char *pdest)
|
||||
{
|
||||
int i;
|
||||
char digit[20];
|
||||
size_t len;
|
||||
|
||||
for (i = 0; val; i++) {
|
||||
epicsUInt64 tenth = val / 10;
|
||||
|
||||
digit[i] = val - tenth * 10 + '0';
|
||||
val = tenth;
|
||||
}
|
||||
|
||||
len = i;
|
||||
while (i > 0)
|
||||
*pdest++ = digit[--i];
|
||||
|
||||
*pdest = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UInt64ToBase(epicsUInt64 val, char *pdest, int base)
|
||||
{
|
||||
int i;
|
||||
char digit, digits[64];
|
||||
size_t len;
|
||||
|
||||
for (i = 0; val; i++) {
|
||||
epicsUInt64 tenth = val / base;
|
||||
|
||||
digit = val - tenth * base;
|
||||
digits[i] = digit < 10 ? digit + '0' : digit - 10 + 'a';
|
||||
val = tenth;
|
||||
}
|
||||
len = i;
|
||||
|
||||
while (i > 0)
|
||||
*pdest++ = digits[--i];
|
||||
|
||||
*pdest = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Integer conversion routines */
|
||||
|
||||
size_t
|
||||
cvtUInt32ToString(epicsUInt32 val, char *pdest)
|
||||
{
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return UInt32ToDec(val, pdest);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtInt32ToString(epicsInt32 val, char *pdest)
|
||||
{
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (val > 0)
|
||||
return UInt32ToDec(val, pdest);
|
||||
|
||||
if (val == -0x80000000) {
|
||||
strcpy(pdest, "-2147483648");
|
||||
return strlen(pdest);
|
||||
}
|
||||
|
||||
*pdest++ = '-';
|
||||
return 1 + UInt32ToDec(-val, pdest);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
cvtUInt64ToString(epicsUInt64 val, char *pdest)
|
||||
{
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return UInt64ToDec(val, pdest);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtInt64ToString(epicsInt64 val, char *pdest)
|
||||
{
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (val > 0)
|
||||
return UInt64ToDec(val, pdest);
|
||||
|
||||
if (val == -0x8000000000000000LL) {
|
||||
strcpy(pdest, "-9223372036854775808");
|
||||
return strlen(pdest);
|
||||
}
|
||||
|
||||
*pdest++ = '-';
|
||||
return 1 + UInt64ToDec(-val, pdest);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
cvtInt32ToHexString(epicsInt32 val, char *pdest)
|
||||
{
|
||||
if (val < 0)
|
||||
*pdest++ = '-';
|
||||
|
||||
*pdest++ = '0';
|
||||
*pdest++ = 'x';
|
||||
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (val > 0)
|
||||
return 2 + UInt32ToBase(val, pdest, 16);
|
||||
|
||||
if (val == -0x80000000) {
|
||||
strcpy(pdest, "80000000");
|
||||
return 11;
|
||||
}
|
||||
|
||||
return 3 + UInt32ToBase(-val, pdest, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtUInt32ToHexString(epicsUInt32 val, char *pdest)
|
||||
{
|
||||
*pdest++ = '0';
|
||||
*pdest++ = 'x';
|
||||
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 2 + UInt32ToBase(val, pdest, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtInt32ToOctalString(epicsInt32 val, char *pdest)
|
||||
{
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (val > 0) {
|
||||
*pdest++ = '0';
|
||||
return 1 + UInt32ToBase(val, pdest, 8);
|
||||
}
|
||||
|
||||
if (val == -0x80000000) {
|
||||
strcpy(pdest, "-020000000000");
|
||||
return strlen(pdest);
|
||||
}
|
||||
|
||||
*pdest++ = '-';
|
||||
*pdest++ = '0';
|
||||
return 2 + UInt32ToBase(-val, pdest, 8);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtInt64ToHexString(epicsInt64 val, char *pdest)
|
||||
{
|
||||
if (val < 0)
|
||||
*pdest++ = '-';
|
||||
|
||||
*pdest++ = '0';
|
||||
*pdest++ = 'x';
|
||||
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (val > 0)
|
||||
return 2 + UInt64ToBase(val, pdest, 16);
|
||||
|
||||
if (val == -0x8000000000000000LL) {
|
||||
strcpy(pdest, "8000000000000000");
|
||||
return 19;
|
||||
}
|
||||
|
||||
return 3 + UInt64ToBase(-val, pdest, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
cvtUInt64ToHexString(epicsUInt64 val, char *pdest)
|
||||
{
|
||||
*pdest++ = '0';
|
||||
*pdest++ = 'x';
|
||||
|
||||
if (val == 0) {
|
||||
*pdest++ = '0';
|
||||
*pdest = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 2 + UInt64ToBase(val, pdest, 16);
|
||||
}
|
||||
|
||||
83
modules/libcom/src/cvtFast/cvtFast.h
Normal file
83
modules/libcom/src/cvtFast/cvtFast.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Fast numeric to string conversions
|
||||
*
|
||||
* Original Authors:
|
||||
* Bob Dalesio, Mark Anderson and Marty Kraimer
|
||||
* Date: 12 January 1993
|
||||
*/
|
||||
|
||||
#ifndef INCcvtFasth
|
||||
#define INCcvtFasth
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All functions return the number of characters in the output
|
||||
*/
|
||||
epicsShareFunc int
|
||||
cvtFloatToString(float val, char *pdest, epicsUInt16 prec);
|
||||
epicsShareFunc int
|
||||
cvtDoubleToString(double val, char *pdest, epicsUInt16 prec);
|
||||
|
||||
epicsShareFunc int
|
||||
cvtFloatToExpString(float val, char *pdest, epicsUInt16 prec);
|
||||
epicsShareFunc int
|
||||
cvtDoubleToExpString(double val, char *pdest, epicsUInt16 prec);
|
||||
epicsShareFunc int
|
||||
cvtFloatToCompactString(float val, char *pdest, epicsUInt16 prec);
|
||||
epicsShareFunc int
|
||||
cvtDoubleToCompactString(double val, char *pdest, epicsUInt16 prec);
|
||||
|
||||
epicsShareFunc size_t
|
||||
cvtInt32ToString(epicsInt32 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtUInt32ToString(epicsUInt32 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtInt64ToString(epicsInt64 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtUInt64ToString(epicsUInt64 val, char *pdest);
|
||||
|
||||
epicsShareFunc size_t
|
||||
cvtInt32ToHexString(epicsInt32 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtUInt32ToHexString(epicsUInt32 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtInt32ToOctalString(epicsInt32 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtInt64ToHexString(epicsInt64 val, char *pdest);
|
||||
epicsShareFunc size_t
|
||||
cvtUInt64ToHexString(epicsUInt64 val, char *pdest);
|
||||
|
||||
/* Support the original names */
|
||||
|
||||
#define cvtCharToString(val, str) cvtInt32ToString(val, str)
|
||||
#define cvtUcharToString(val, str) cvtUInt32ToString(val, str)
|
||||
#define cvtShortToString(val, str) cvtInt32ToString(val, str)
|
||||
#define cvtUshortToString(val, str) cvtUInt32ToString(val, str)
|
||||
#define cvtLongToString(val, str) cvtInt32ToString(val, str)
|
||||
#define cvtUlongToString(val, str) cvtUInt32ToString(val, str)
|
||||
|
||||
#define cvtLongToHexString(val, str) cvtInt32ToHexString(val, str)
|
||||
#define cvtULongToHexString(val, str) cvtUInt32ToHexString(val, str)
|
||||
#define cvtLongToOctalString(val, str) cvtInt32ToOctalString(val, str)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCcvtFasth*/
|
||||
20
modules/libcom/src/cxxTemplates/Makefile
Normal file
20
modules/libcom/src/cxxTemplates/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/cxxTemplates
|
||||
INC += resourceLib.h
|
||||
INC += tsDLList.h
|
||||
INC += tsSLList.h
|
||||
INC += tsMinMax.h
|
||||
INC += tsFreeList.h
|
||||
INC += epicsSingleton.h
|
||||
INC += epicsGuard.h
|
||||
Com_SRCS += resourceLib.cpp
|
||||
Com_SRCS += epicsSingletonMutex.cpp
|
||||
|
||||
35
modules/libcom/src/cxxTemplates/README
Normal file
35
modules/libcom/src/cxxTemplates/README
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
C++ templates:
|
||||
tsSLList.h - type safe single linked list template
|
||||
tsDLList.h - type safe double linked list template
|
||||
resourceLib.h - hash table template
|
||||
tsFreeeList.h - free list allocator / deallocator
|
||||
|
||||
the test subdir contains examples
|
||||
|
||||
Since I am using templates the linked lists are type safe
|
||||
(no casting of pointers ala ellList and dllList).
|
||||
Also, the node class in embedded in the item on the
|
||||
list (more efficient use of pool).
|
||||
|
||||
The file resourceLib.h provides a core hashing library
|
||||
"resTable <itemClass, idClass>" where "itemClass" objects
|
||||
are stored in the hash table and "idClass" is the data type
|
||||
of the key for the hash table. The identifier class provides
|
||||
the hash alg. I have provided simple string "stringId" and
|
||||
unsigned integer "uintId" key types in resourceLib.h. It
|
||||
is easy to implement a new key class.
|
||||
|
||||
There are examples under cxxTemplate/test. The list/hashing
|
||||
templates all depend on a particular inheritance hierarchy.
|
||||
If the inheritance hierarchy is wrong nothing will compile.
|
||||
For instance, in tsDLList.h the template data type "T"
|
||||
must derive from tsDLNode<T>. Likewise, in tsSLList.h
|
||||
"T" must derive from tsSLNode<T>. Likewise, in resourceLib.h
|
||||
class "T" (the type stored in the hash table) must derive
|
||||
from class "ID" (the hash table key type) and also derive from
|
||||
tsSLNode<T>.
|
||||
|
||||
|
||||
|
||||
|
||||
114
modules/libcom/src/cxxTemplates/epicsGuard.h
Normal file
114
modules/libcom/src/cxxTemplates/epicsGuard.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef epicsGuardh
|
||||
#define epicsGuardh
|
||||
|
||||
#ifndef assert // allow use of epicsAssert.h
|
||||
# include <cassert>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
*/
|
||||
|
||||
template < class T > class epicsGuardRelease;
|
||||
|
||||
// Automatically applies and releases the mutex.
|
||||
// This class is also useful in situations where
|
||||
// C++ exceptions are possible.
|
||||
template < class T >
|
||||
class epicsGuard {
|
||||
public:
|
||||
typedef epicsGuardRelease<T> release_t;
|
||||
epicsGuard ( T & );
|
||||
void assertIdenticalMutex ( const T & ) const;
|
||||
~epicsGuard ();
|
||||
private:
|
||||
T * _pTargetMutex;
|
||||
epicsGuard ( const epicsGuard & );
|
||||
epicsGuard & operator = ( const epicsGuard & );
|
||||
friend class epicsGuardRelease < T >;
|
||||
};
|
||||
|
||||
// Automatically releases and reapplies the mutex.
|
||||
// This class is also useful in situations where
|
||||
// C++ exceptions are possible.
|
||||
template < class T >
|
||||
class epicsGuardRelease {
|
||||
public:
|
||||
typedef epicsGuard<T> guard_t;
|
||||
epicsGuardRelease ( epicsGuard < T > & );
|
||||
~epicsGuardRelease ();
|
||||
private:
|
||||
epicsGuard < T > & _guard;
|
||||
T * _pTargetMutex;
|
||||
epicsGuardRelease ( const epicsGuardRelease & );
|
||||
epicsGuardRelease & operator = ( const epicsGuardRelease & );
|
||||
};
|
||||
|
||||
// same interface as epicsMutex
|
||||
class epicsMutexNOOP {
|
||||
public:
|
||||
void lock ();
|
||||
bool tryLock ();
|
||||
void unlock ();
|
||||
void show ( unsigned level ) const;
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline epicsGuard < T > :: epicsGuard ( T & mutexIn ) :
|
||||
_pTargetMutex ( & mutexIn )
|
||||
{
|
||||
_pTargetMutex->lock ();
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline epicsGuard < T > :: ~epicsGuard ()
|
||||
{
|
||||
_pTargetMutex->unlock ();
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline void epicsGuard < T > :: assertIdenticalMutex (
|
||||
const T & mutexToVerify ) const
|
||||
{
|
||||
assert ( _pTargetMutex == & mutexToVerify );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline epicsGuardRelease < T > ::
|
||||
epicsGuardRelease ( epicsGuard<T> & guardIn ) :
|
||||
_guard ( guardIn ),
|
||||
_pTargetMutex ( guardIn._pTargetMutex )
|
||||
{
|
||||
// Setting the guard's _pTargetMutex to nill will
|
||||
// allow assertIdenticalMutex to catch situations
|
||||
// where a guard is being used and it has been
|
||||
// released, and also situations where ~epicsGuard ()
|
||||
// runs and an epicsGuardRelease is still referencing
|
||||
// the guard will be detected.
|
||||
_guard._pTargetMutex = 0;
|
||||
_pTargetMutex->unlock ();
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline epicsGuardRelease < T > :: ~epicsGuardRelease ()
|
||||
{
|
||||
_pTargetMutex->lock ();
|
||||
_guard._pTargetMutex = _pTargetMutex;
|
||||
}
|
||||
|
||||
inline void epicsMutexNOOP::lock () {}
|
||||
inline bool epicsMutexNOOP::tryLock () { return true; }
|
||||
inline void epicsMutexNOOP::unlock () {}
|
||||
inline void epicsMutexNOOP::show ( unsigned ) const {}
|
||||
|
||||
#endif // epicsGuardh
|
||||
216
modules/libcom/src/cxxTemplates/epicsSingleton.h
Normal file
216
modules/libcom/src/cxxTemplates/epicsSingleton.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
*/
|
||||
|
||||
#ifndef epicsSingleton_h
|
||||
#define epicsSingleton_h
|
||||
|
||||
#include <new>
|
||||
#include <cstddef>
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "epicsAssert.h"
|
||||
|
||||
class epicsShareClass SingletonUntyped {
|
||||
public:
|
||||
SingletonUntyped ();
|
||||
~SingletonUntyped ();
|
||||
typedef void * ( * PBuild ) ();
|
||||
void incrRefCount ( PBuild );
|
||||
typedef void ( * PDestroy ) ( void * );
|
||||
void decrRefCount ( PDestroy );
|
||||
void * pInstance () const;
|
||||
private:
|
||||
void * _pInstance;
|
||||
std :: size_t _refCount;
|
||||
SingletonUntyped ( const SingletonUntyped & );
|
||||
SingletonUntyped & operator = ( const SingletonUntyped & );
|
||||
};
|
||||
|
||||
// This class exists for the purpose of avoiding file scope
|
||||
// object chicken and egg problems. It implements thread safe
|
||||
// lazy initialization. To avoid locking overhead retain a
|
||||
// copy of the epicsSingleton :: reference for future use.
|
||||
template < class TYPE >
|
||||
class epicsSingleton {
|
||||
public:
|
||||
class reference {
|
||||
public:
|
||||
reference ( epicsSingleton & );
|
||||
reference ( const reference & );
|
||||
~reference ();
|
||||
// this somewhat convoluted reference of the return
|
||||
// type ref through the epicsSingleton template is
|
||||
// required for the archaic Tornado gnu compiler
|
||||
typename epicsSingleton < TYPE > :: reference &
|
||||
operator = ( const reference & );
|
||||
TYPE * operator -> ();
|
||||
const TYPE * operator -> () const;
|
||||
TYPE & operator * ();
|
||||
const TYPE & operator * () const;
|
||||
private:
|
||||
epicsSingleton * _pSingleton;
|
||||
};
|
||||
friend class reference;
|
||||
epicsSingleton () {}
|
||||
// mutex lock/unlock pair overhead incured
|
||||
// when either of these are called
|
||||
reference getReference ();
|
||||
const reference getReference () const;
|
||||
private:
|
||||
SingletonUntyped _singletonUntyped;
|
||||
static void * _build ();
|
||||
static void _destroy ( void * );
|
||||
epicsSingleton ( const epicsSingleton & );
|
||||
epicsSingleton & operator = ( const epicsSingleton & );
|
||||
};
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
reference ( epicsSingleton & es ):
|
||||
_pSingleton ( & es )
|
||||
{
|
||||
es._singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
reference ( const reference & ref ) :
|
||||
_pSingleton ( ref._pSingleton )
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline epicsSingleton < TYPE > :: reference ::
|
||||
~reference ()
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( & epicsSingleton < TYPE > :: _destroy );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
typename epicsSingleton < TYPE > :: reference &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator = ( const reference & ref )
|
||||
{
|
||||
if ( _pSingleton != ref._pSingleton ) {
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
decrRefCount ( epicsSingleton < TYPE > :: _destroy );
|
||||
_pSingleton = ref._pSingleton;
|
||||
assert ( _pSingleton );
|
||||
_pSingleton->_singletonUntyped.
|
||||
incrRefCount ( & epicsSingleton < TYPE > :: _build );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline TYPE *
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator -> ()
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const TYPE *
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator -> () const
|
||||
{
|
||||
assert ( _pSingleton );
|
||||
return reinterpret_cast < const TYPE * >
|
||||
( _pSingleton->_singletonUntyped.pInstance () );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline TYPE &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator * ()
|
||||
{
|
||||
return * this->operator -> ();
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const TYPE &
|
||||
epicsSingleton < TYPE > :: reference ::
|
||||
operator * () const
|
||||
{
|
||||
return * this->operator -> ();
|
||||
}
|
||||
|
||||
inline SingletonUntyped :: SingletonUntyped () :
|
||||
_pInstance ( 0 ), _refCount ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
inline void * SingletonUntyped :: pInstance () const
|
||||
{
|
||||
return _pInstance;
|
||||
}
|
||||
|
||||
inline SingletonUntyped :: ~SingletonUntyped ()
|
||||
{
|
||||
// we dont assert fail on non-zero _refCount
|
||||
// and or non nill _pInstance here because this
|
||||
// is designed to tolarate situations where
|
||||
// file scope epicsSingleton objects (which
|
||||
// theoretically dont have storage lifespan
|
||||
// issues) are deleted in a non-determanistic
|
||||
// order
|
||||
# if 0
|
||||
assert ( _refCount == 0 );
|
||||
assert ( _pInstance == 0 );
|
||||
# endif
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
void * epicsSingleton < TYPE > :: _build ()
|
||||
{
|
||||
return new TYPE ();
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
void epicsSingleton < TYPE > ::
|
||||
_destroy ( void * pDestroyTypeless )
|
||||
{
|
||||
TYPE * pDestroy =
|
||||
reinterpret_cast < TYPE * > ( pDestroyTypeless );
|
||||
delete pDestroy;
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline typename epicsSingleton < TYPE > :: reference
|
||||
epicsSingleton < TYPE > :: getReference ()
|
||||
{
|
||||
return reference ( * this );
|
||||
}
|
||||
|
||||
template < class TYPE >
|
||||
inline const typename epicsSingleton < TYPE > :: reference
|
||||
epicsSingleton < TYPE > :: getReference () const
|
||||
{
|
||||
epicsSingleton < TYPE > * pConstCastAway =
|
||||
const_cast < epicsSingleton < TYPE > * > ( this );
|
||||
return pConstCastAway->getReference ();
|
||||
}
|
||||
|
||||
#endif // epicsSingleton_h
|
||||
|
||||
60
modules/libcom/src/cxxTemplates/epicsSingletonMutex.cpp
Normal file
60
modules/libcom/src/cxxTemplates/epicsSingletonMutex.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Jeff O. Hill
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsSingleton.h"
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX UINT_MAX
|
||||
#endif
|
||||
|
||||
static epicsThreadOnceId epicsSigletonOnceFlag ( EPICS_THREAD_ONCE_INIT );
|
||||
static epicsMutex * pEPICSSigletonMutex = 0;
|
||||
|
||||
extern "C" void SingletonMutexOnce ( void * /* pParm */ )
|
||||
{
|
||||
// This class exists for the purpose of avoiding file scope
|
||||
// object chicken and egg problems. Therefore, pEPICSSigletonMutex
|
||||
// is never destroyed.
|
||||
pEPICSSigletonMutex = newEpicsMutex;
|
||||
}
|
||||
|
||||
void SingletonUntyped :: incrRefCount ( PBuild pBuild )
|
||||
{
|
||||
epicsThreadOnce ( & epicsSigletonOnceFlag, SingletonMutexOnce, 0 );
|
||||
epicsGuard < epicsMutex >
|
||||
guard ( *pEPICSSigletonMutex );
|
||||
assert ( _refCount < SIZE_MAX );
|
||||
if ( _refCount == 0 ) {
|
||||
_pInstance = ( * pBuild ) ();
|
||||
}
|
||||
_refCount++;
|
||||
}
|
||||
|
||||
void SingletonUntyped :: decrRefCount ( PDestroy pDestroy )
|
||||
{
|
||||
epicsGuard < epicsMutex >
|
||||
guard ( *pEPICSSigletonMutex );
|
||||
assert ( _refCount > 0 );
|
||||
_refCount--;
|
||||
if ( _refCount == 0 ) {
|
||||
( *pDestroy ) ( _pInstance );
|
||||
_pInstance = 0;
|
||||
}
|
||||
}
|
||||
25
modules/libcom/src/cxxTemplates/resourceLib.cpp
Normal file
25
modules/libcom/src/cxxTemplates/resourceLib.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "resourceLib.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class intId < unsigned, 8u, sizeof(unsigned)*CHAR_BIT >;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
1170
modules/libcom/src/cxxTemplates/resourceLib.h
Normal file
1170
modules/libcom/src/cxxTemplates/resourceLib.h
Normal file
File diff suppressed because it is too large
Load Diff
35
modules/libcom/src/cxxTemplates/test/Makefile
Normal file
35
modules/libcom/src/cxxTemplates/test/Makefile
Normal file
@@ -0,0 +1,35 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
resourceLibTest_SRCS += resourceLibTest.cc
|
||||
TESTPROD_HOST += resourceLibTest
|
||||
|
||||
tsDLListBench_SRCS += tsDLListBench.cc
|
||||
TESTPROD_HOST += tsDLListBench
|
||||
|
||||
tsDLListTest_SRCS += tsDLListTest.cc
|
||||
TESTPROD_HOST += tsDLListTest
|
||||
|
||||
tsSLListBench_SRCS += tsSLListBench.cc
|
||||
TESTPROD_HOST += tsSLListBench
|
||||
|
||||
tsSLListTest_SRCS += tsSLListTest.cc
|
||||
TESTPROD_HOST += tsSLListTest
|
||||
|
||||
minmaxTest_SRCS += minmaxTest.cc
|
||||
TESTPROD_HOST += minmaxTest
|
||||
|
||||
PROD_LIBS = Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
39
modules/libcom/src/cxxTemplates/test/minmaxTest.cc
Normal file
39
modules/libcom/src/cxxTemplates/test/minmaxTest.cc
Normal file
@@ -0,0 +1,39 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "tsMinMax.h"
|
||||
|
||||
int main ()
|
||||
{
|
||||
float f1 = 3.3f;
|
||||
float f2 = 3.4f;
|
||||
float f3;
|
||||
|
||||
f3 = tsMin(f1,f2);
|
||||
assert(f3==f1);
|
||||
|
||||
f3 = tsMax(f1,f2);
|
||||
assert(f3==f2);
|
||||
|
||||
int i1 = 3;
|
||||
int i2 = 4;
|
||||
int i3;
|
||||
|
||||
i3 = tsMin(i1,i2);
|
||||
assert(i3==i1);
|
||||
|
||||
i3 = tsMax(i1,i2);
|
||||
assert(i3==i2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
309
modules/libcom/src/cxxTemplates/test/resourceLibTest.cc
Normal file
309
modules/libcom/src/cxxTemplates/test/resourceLibTest.cc
Normal file
@@ -0,0 +1,309 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define instantiateRecourceLib
|
||||
#include "resourceLib.h"
|
||||
|
||||
#if defined(__GNUC__) && ( __GNUC__<2 || (__GNUC__==2 && __GNUC__<8) )
|
||||
typedef intId<unsigned,8,16> testIntId;
|
||||
#else
|
||||
typedef intId<unsigned,8> testIntId;
|
||||
#endif
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
static void empty()
|
||||
{
|
||||
}
|
||||
|
||||
class albert : public testIntId, public tsSLNode<albert> {
|
||||
public:
|
||||
albert (resTable< albert, testIntId > &atIn, unsigned idIn) :
|
||||
testIntId(idIn), at(atIn)
|
||||
{
|
||||
verify (at.add (*this)==0);
|
||||
}
|
||||
void show (unsigned /* level */)
|
||||
{
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
at.remove(*this);
|
||||
delete this;
|
||||
}
|
||||
private:
|
||||
resTable< albert, testIntId > &at;
|
||||
};
|
||||
|
||||
class fred : public testIntId, public tsSLNode<fred> {
|
||||
public:
|
||||
fred (const char *pNameIn, unsigned idIn) :
|
||||
testIntId(idIn), pName(pNameIn) {}
|
||||
void show (unsigned)
|
||||
{
|
||||
printf("fred %s\n", pName);
|
||||
}
|
||||
void destroy()
|
||||
{
|
||||
// always on stack so noop
|
||||
}
|
||||
private:
|
||||
const char * const pName;
|
||||
};
|
||||
|
||||
class jane : public stringId, public tsSLNode<jane> {
|
||||
public:
|
||||
jane (const char *pNameIn) : stringId (pNameIn) {}
|
||||
|
||||
void testTraverse();
|
||||
|
||||
void destroy()
|
||||
{
|
||||
// always on stack so noop
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// jane::testTraverse()
|
||||
//
|
||||
void jane::testTraverse()
|
||||
{
|
||||
printf("Traverse Test\n");
|
||||
this->show(10);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
unsigned i;
|
||||
clock_t start, finish;
|
||||
double duration;
|
||||
const unsigned LOOPS = 500000;
|
||||
resTable < fred, testIntId > intTbl;
|
||||
resTable < jane, stringId> strTbl;
|
||||
fred fred0("fred0",0);
|
||||
fred fred1("fred1",0x1000a432);
|
||||
fred fred2("fred2",0x0000a432);
|
||||
fred fred3("fred3",1);
|
||||
fred fred4("fred4",2);
|
||||
fred fred5("fred5",3);
|
||||
fred fred6("fred6",4);
|
||||
fred fred7("fred7",5);
|
||||
fred fred8("fred8",6);
|
||||
fred fred9("fred9",7);
|
||||
jane jane1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
|
||||
jane jane2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
|
||||
fred *pFred;
|
||||
jane *pJane;
|
||||
testIntId intId0 (0);
|
||||
testIntId intId1 (0x1000a432);
|
||||
testIntId intId2 (0x0000a432);
|
||||
testIntId intId3 (1);
|
||||
testIntId intId4 (2);
|
||||
testIntId intId5 (3);
|
||||
testIntId intId6 (4);
|
||||
testIntId intId7 (5);
|
||||
testIntId intId8 (6);
|
||||
testIntId intId9 (7);
|
||||
|
||||
stringId strId1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
|
||||
strTbl.verify ();
|
||||
stringId strId2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
|
||||
strTbl.verify ();
|
||||
|
||||
intTbl.setTableSize ( 100000 );
|
||||
|
||||
verify (intTbl.add(fred0)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred1)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred2)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred3)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred4)==0);
|
||||
intTbl.verify ();
|
||||
|
||||
intTbl.setTableSize ( 200000 );
|
||||
|
||||
verify (intTbl.add(fred5)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred6)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred7)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred8)==0);
|
||||
intTbl.verify ();
|
||||
verify (intTbl.add(fred9)==0);
|
||||
intTbl.verify ();
|
||||
|
||||
start = clock();
|
||||
for (i=0; i<LOOPS; i++) {
|
||||
pFred = intTbl.lookup(intId1);
|
||||
verify(pFred==&fred1);
|
||||
pFred = intTbl.lookup(intId2);
|
||||
verify (pFred==&fred2);
|
||||
pFred = intTbl.lookup(intId3);
|
||||
verify (pFred==&fred3);
|
||||
pFred = intTbl.lookup(intId4);
|
||||
verify (pFred==&fred4);
|
||||
pFred = intTbl.lookup(intId5);
|
||||
verify (pFred==&fred5);
|
||||
pFred = intTbl.lookup(intId6);
|
||||
verify (pFred==&fred6);
|
||||
pFred = intTbl.lookup(intId7);
|
||||
verify (pFred==&fred7);
|
||||
pFred = intTbl.lookup(intId8);
|
||||
verify (pFred==&fred8);
|
||||
pFred = intTbl.lookup(intId9);
|
||||
verify (pFred==&fred9);
|
||||
pFred = intTbl.lookup(intId0);
|
||||
verify (pFred==&fred0);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
duration = finish-start;
|
||||
duration /= CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec for integer hash lookups\n", duration);
|
||||
duration /= LOOPS;
|
||||
duration /= 10;
|
||||
duration *= 1e6;
|
||||
printf("It took %15.10f u sec per integer hash lookup\n", duration);
|
||||
|
||||
intTbl.show(10u);
|
||||
|
||||
intTbl.remove(intId1);
|
||||
intTbl.remove(intId2);
|
||||
pFred = intTbl.lookup(intId1);
|
||||
verify (pFred==0);
|
||||
pFred = intTbl.lookup(intId2);
|
||||
verify (pFred==0);
|
||||
|
||||
verify (strTbl.add(jane1)==0);
|
||||
verify (strTbl.add(jane2)==0);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId1);
|
||||
verify (pJane==&jane1);
|
||||
pJane = strTbl.lookup(strId2);
|
||||
verify (pJane==&jane2);
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
duration = finish-start;
|
||||
duration /= CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec for string hash lookups\n", duration);
|
||||
duration /= LOOPS;
|
||||
duration /= 10;
|
||||
duration *= 1e6;
|
||||
printf("It took %15.10f u sec per string hash lookup\n", duration);
|
||||
|
||||
strTbl.show(10u);
|
||||
strTbl.traverse(&jane::testTraverse);
|
||||
|
||||
strTbl.remove(strId1);
|
||||
strTbl.remove(strId2);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
strlen ( "0" );
|
||||
strlen ( "1" );
|
||||
strlen ( "2" );
|
||||
strlen ( "3" );
|
||||
strlen ( "4" );
|
||||
strlen ( "5" );
|
||||
strlen ( "6" );
|
||||
strlen ( "7" );
|
||||
strlen ( "8" );
|
||||
strlen ( "9" );
|
||||
}
|
||||
finish = clock();
|
||||
duration = finish-start;
|
||||
duration /= CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec for minimal subroutines\n", duration);
|
||||
duration /= LOOPS;
|
||||
duration /= 10;
|
||||
duration *= 1e6;
|
||||
printf("It took %15.10f u sec to call a minimal subroutine\n", duration);
|
||||
|
||||
//
|
||||
// hash distribution test
|
||||
//
|
||||
static const unsigned elementCount = 0x8000;
|
||||
albert *pAlbert[elementCount];
|
||||
resTable< albert, testIntId > alTbl;
|
||||
|
||||
for (i=0; i<elementCount; i++) {
|
||||
pAlbert[i] = new albert (alTbl, i);
|
||||
verify ( pAlbert[i] );
|
||||
}
|
||||
alTbl.verify ();
|
||||
alTbl.show (1u);
|
||||
|
||||
resTableIter < albert, testIntId > alTblIter ( alTbl.firstIter() );
|
||||
albert *pa;
|
||||
i=0;
|
||||
while ( ( pa = alTblIter.pointer() ) ) {
|
||||
i++;
|
||||
alTblIter++;
|
||||
}
|
||||
verify ( i == elementCount );
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i++ ) {
|
||||
verify ( pAlbert[i] == alTbl.lookup( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i += 2 ) {
|
||||
verify ( pAlbert[i] == alTbl.remove ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 0; i < elementCount; i += 2 ) {
|
||||
verify ( 0 == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
for ( i = 1; i < elementCount; i += 2 ) {
|
||||
verify ( pAlbert[i] == alTbl.lookup ( pAlbert[i]->getId() ) );
|
||||
}
|
||||
alTbl.verify ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
71
modules/libcom/src/cxxTemplates/test/tsDLListBench.cc
Normal file
71
modules/libcom/src/cxxTemplates/test/tsDLListBench.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
class fred : public tsDLNode<fred> {
|
||||
public:
|
||||
fred() : count(0) {}
|
||||
void inc () {count++;}
|
||||
private:
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
class jane : public fred, public tsDLNode<jane> {
|
||||
public:
|
||||
jane() {}
|
||||
private:
|
||||
};
|
||||
|
||||
#define LOOPCOUNT 100000
|
||||
|
||||
int main ()
|
||||
{
|
||||
tsDLList<fred> list;
|
||||
tsDLIter<fred> iter = list.firstIter();
|
||||
fred *pFred;
|
||||
unsigned i;
|
||||
clock_t clk;
|
||||
clock_t diff;
|
||||
double delay;
|
||||
|
||||
for (i=0; i<LOOPCOUNT; i++) {
|
||||
pFred = new fred();
|
||||
list.add(*pFred);
|
||||
}
|
||||
|
||||
clk = clock();
|
||||
while ( iter.valid() ) {
|
||||
iter->inc();
|
||||
iter++;
|
||||
}
|
||||
diff = clock() - clk;
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf("delay = %15.10f\n", delay);
|
||||
|
||||
pFred = new fred();
|
||||
clk = clock();
|
||||
for (i=0; i<LOOPCOUNT; i++) {
|
||||
pFred->inc();
|
||||
}
|
||||
diff = clock() - clk;
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf("delay = %15.10f\n", delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
131
modules/libcom/src/cxxTemplates/test/tsDLListTest.cc
Normal file
131
modules/libcom/src/cxxTemplates/test/tsDLListTest.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define verify(exp) ((exp) ? (void)0 : \
|
||||
epicsAssert(__FILE__, __LINE__, #exp, epicsAssertAuthor))
|
||||
|
||||
class fred : public tsDLNode<fred> {
|
||||
public:
|
||||
fred(const char * const pNameIn) : pName(pNameIn){}
|
||||
void show () {printf("%s\n", pName);}
|
||||
private:
|
||||
const char * const pName;
|
||||
};
|
||||
|
||||
class jane : public fred, public tsDLNode<jane> {
|
||||
public:
|
||||
jane(const char * const pNameIn) : fred(pNameIn){}
|
||||
private:
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
unsigned i;
|
||||
tsDLList<fred> list;
|
||||
fred *pFred;
|
||||
fred *pFredII;
|
||||
fred *pFredBack;
|
||||
tsDLList<jane> janeList;
|
||||
tsDLIter<jane> janeFwdIter = janeList.firstIter();
|
||||
tsDLIter<jane> janeBwdIter = janeList.lastIter();
|
||||
jane *pJane;
|
||||
|
||||
pFred = new fred ("A");
|
||||
pFredII = new fred ("B");
|
||||
|
||||
list.add (*pFred);
|
||||
list.add (*pFredII);
|
||||
tsDLIter <fred> iter = list.firstIter();
|
||||
verify (iter.pointer() == pFred);
|
||||
iter++;
|
||||
verify (iter.pointer() == pFredII);
|
||||
list.remove(*pFred);
|
||||
list.add(*pFred);
|
||||
pFredBack = list.get();
|
||||
verify (pFredBack == pFredII);
|
||||
pFredBack = list.get();
|
||||
verify (pFredBack == pFred);
|
||||
verify (list.count() == 0u);
|
||||
list.add(*pFred);
|
||||
list.add(*pFredII);
|
||||
list.add(* new fred("C"));
|
||||
list.add(* new fred("D"));
|
||||
|
||||
iter = list.firstIter();
|
||||
while ( iter.valid() ) {
|
||||
iter->show();
|
||||
iter++;
|
||||
}
|
||||
|
||||
pJane = new jane("JA");
|
||||
janeList.add(*pJane);
|
||||
pJane = new jane("JB");
|
||||
verify ( janeList.find ( *pJane ) == -1 );
|
||||
janeList.add(*pJane);
|
||||
verify ( janeList.find ( *pJane ) == 1 );
|
||||
|
||||
while ( janeFwdIter.valid() ) {
|
||||
janeFwdIter->show();
|
||||
janeFwdIter++;
|
||||
}
|
||||
|
||||
while ( janeBwdIter.valid() ) {
|
||||
janeBwdIter->show();
|
||||
janeBwdIter--;
|
||||
}
|
||||
|
||||
iter = list.firstIter();
|
||||
while ( iter.valid() ) {
|
||||
iter->show();
|
||||
iter++;
|
||||
}
|
||||
|
||||
tsDLIter < jane > bdIter = janeList.firstIter ();
|
||||
i = 0;
|
||||
while ( bdIter.valid () ) {
|
||||
i++;
|
||||
bdIter++;
|
||||
}
|
||||
verify ( i == janeList.count () );
|
||||
|
||||
iter = list.firstIter();
|
||||
while ( iter.pointer() ) {
|
||||
list.remove( * iter.pointer() );
|
||||
iter++;
|
||||
}
|
||||
verify (list.count()==0);
|
||||
|
||||
janeFwdIter = janeList.firstIter();
|
||||
while ( janeFwdIter.valid() ) {
|
||||
janeList.remove( * janeFwdIter.pointer() );
|
||||
janeFwdIter++;
|
||||
}
|
||||
verify (janeList.count()==0);
|
||||
|
||||
pJane = new jane("JA");
|
||||
janeList.add(*pJane);
|
||||
pJane = new jane("JB");
|
||||
janeList.add(*pJane);
|
||||
janeBwdIter = janeList.lastIter();
|
||||
while ( janeBwdIter.valid() ) {
|
||||
janeList.remove( * janeBwdIter.pointer() );
|
||||
janeBwdIter--;
|
||||
}
|
||||
verify (janeList.count()==0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
85
modules/libcom/src/cxxTemplates/test/tsSLListBench.cc
Normal file
85
modules/libcom/src/cxxTemplates/test/tsSLListBench.cc
Normal file
@@ -0,0 +1,85 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include "tsSLList.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* gnuc does not provide this under sunos4
|
||||
*/
|
||||
#if !defined(CLOCKS_PER_SEC) && defined(SUNOS4)
|
||||
# define CLOCKS_PER_SEC 1000000
|
||||
#endif
|
||||
|
||||
class fred : public tsSLNode<fred> {
|
||||
public:
|
||||
fred() : count(0) {}
|
||||
void inc () {count++;}
|
||||
private:
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
class jane : public fred, public tsSLNode<jane> {
|
||||
public:
|
||||
jane() {}
|
||||
private:
|
||||
};
|
||||
|
||||
#define LOOPCOUNT 100000
|
||||
|
||||
int main ()
|
||||
{
|
||||
tsSLList<fred> list;
|
||||
fred *pFred;
|
||||
unsigned i;
|
||||
clock_t clk;
|
||||
clock_t diff;
|
||||
double delay;
|
||||
|
||||
for (i=0; i<LOOPCOUNT; i++) {
|
||||
pFred = new fred();
|
||||
list.add(*pFred);
|
||||
}
|
||||
|
||||
clk = clock();
|
||||
{
|
||||
tsSLIter <fred> iter ( list.firstIter () );
|
||||
while ( iter.valid () ) {
|
||||
iter->inc ();
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
diff = clock() - clk;
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf("delay = %15.10f\n", delay);
|
||||
|
||||
pFred = new fred();
|
||||
clk = clock();
|
||||
{
|
||||
tsSLIter <fred> iter ( list.firstIter () );
|
||||
for ( i=0; i<LOOPCOUNT; i++ ) {
|
||||
iter->inc();
|
||||
}
|
||||
}
|
||||
diff = clock() - clk;
|
||||
delay = diff;
|
||||
delay = delay/CLOCKS_PER_SEC;
|
||||
delay = delay/LOOPCOUNT;
|
||||
printf("delay = %15.10f\n", delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
106
modules/libcom/src/cxxTemplates/test/tsSLListTest.cc
Normal file
106
modules/libcom/src/cxxTemplates/test/tsSLListTest.cc
Normal file
@@ -0,0 +1,106 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include "tsSLList.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
class fred : public tsSLNode<fred> {
|
||||
public:
|
||||
fred(const char * const pNameIn) : pName(pNameIn){}
|
||||
void show () {printf("%s\n", pName);}
|
||||
private:
|
||||
const char * const pName;
|
||||
};
|
||||
|
||||
class jane : public fred, public tsSLNode<jane> {
|
||||
public:
|
||||
jane(const char * const pNameIn) : fred(pNameIn){}
|
||||
private:
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
tsSLList<fred> list;
|
||||
fred *pFred;
|
||||
fred *pFredII;
|
||||
fred *pFredBack;
|
||||
tsSLList<jane> janeList;
|
||||
jane *pJane;
|
||||
|
||||
pFred = new fred("A");
|
||||
pFredII = new fred("B");
|
||||
|
||||
list.add(*pFred);
|
||||
list.add(*pFredII);
|
||||
{
|
||||
tsSLIter<fred> iter1 = list.firstIter ();
|
||||
tsSLIter<fred> iter2 = iter1;
|
||||
tsSLIter<fred> iter3 = iter1;
|
||||
assert ( iter1 == iter3++ );
|
||||
assert ( iter3 == ++iter2 );
|
||||
list.remove ( *pFredII ); // removes pFred
|
||||
}
|
||||
list.add ( *pFred );
|
||||
pFredBack = list.get();
|
||||
assert (pFredBack == pFred);
|
||||
pFredBack = list.get();
|
||||
assert (pFredBack == pFredII);
|
||||
list.add(*pFredII);
|
||||
list.add(*pFred);
|
||||
while ( list.get () );
|
||||
pFredBack = list.get();
|
||||
assert (pFredBack == 0);
|
||||
list.add(*pFred);
|
||||
list.add(*pFredII);
|
||||
list.add(* new fred("C"));
|
||||
list.add(* new fred("D"));
|
||||
|
||||
{
|
||||
tsSLIter < fred > iter = list.firstIter();
|
||||
while ( iter.valid () ) {
|
||||
iter->show();
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
pJane = new jane("JA");
|
||||
janeList.add(*pJane);
|
||||
pJane = new jane("JB");
|
||||
janeList.add(*pJane);
|
||||
|
||||
{
|
||||
tsSLIter < jane > iter = janeList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
iter->show();
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tsSLIter < fred > iter = list.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
iter->show ();
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
while ( list.get () );
|
||||
|
||||
{
|
||||
tsSLIter < fred > iter = list.firstIter ();
|
||||
assert ( ! iter.valid () );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
684
modules/libcom/src/cxxTemplates/tsDLList.h
Normal file
684
modules/libcom/src/cxxTemplates/tsDLList.h
Normal file
@@ -0,0 +1,684 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* type safe doubly linked list templates
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef tsDLListH_include
|
||||
#define tsDLListH_include
|
||||
|
||||
template <class T> class tsDLList;
|
||||
template <class T> class tsDLIterConst;
|
||||
template <class T> class tsDLIter;
|
||||
|
||||
//
|
||||
// class tsDLNode<T>
|
||||
//
|
||||
// a node in a doubly linked list containing entries of type T
|
||||
// ( class T must publicly derive from class tsDLNode<T> )
|
||||
//
|
||||
template < class T >
|
||||
class tsDLNode {
|
||||
public:
|
||||
tsDLNode ();
|
||||
tsDLNode ( const tsDLNode<T> & );
|
||||
const tsDLNode <T> & operator = ( const tsDLNode<T> & );
|
||||
private:
|
||||
T * pNext;
|
||||
T * pPrev;
|
||||
friend class tsDLList<T>;
|
||||
friend class tsDLIter<T>;
|
||||
friend class tsDLIterConst<T>;
|
||||
};
|
||||
|
||||
//
|
||||
// class tsDLList<T>
|
||||
//
|
||||
// a doubly linked list containing entries of type T
|
||||
// ( class T must publicly derive from class tsDLNode<T> )
|
||||
//
|
||||
template < class T >
|
||||
class tsDLList {
|
||||
public:
|
||||
tsDLList (); // create empty list
|
||||
unsigned count () const; // number of items on list
|
||||
void add ( T & item ); // add item to end of list
|
||||
void add ( tsDLList<T> & addList ); // add to end of list - addList left empty
|
||||
void push ( T & item ); // add item to beginning of list
|
||||
void push ( tsDLList<T> & pushList ); // add to beg of list - pushList left empty
|
||||
void remove ( T & item ); // remove item from list
|
||||
void removeAll ( tsDLList <T> & destination );
|
||||
T * get (); // removes first item on list
|
||||
T * pop (); // same as get ()
|
||||
void insertAfter ( T & item, T & itemBefore ); // insert item immediately after itemBefore
|
||||
void insertBefore ( T & item, T & itemAfter ); // insert item immediately before itemAfter
|
||||
int find ( const T & item ) const; // returns -1 if not present, node number if present
|
||||
T * first ( void ) const; // ptr to first item on list
|
||||
T * last ( void ) const; // ptr to last item on list
|
||||
tsDLIterConst <T> firstIter () const;
|
||||
tsDLIter <T> firstIter ();
|
||||
tsDLIterConst <T> lastIter () const;
|
||||
tsDLIter <T> lastIter ();
|
||||
static tsDLIterConst <T> invalidConstIter ();
|
||||
static tsDLIter <T> invalidIter ();
|
||||
private:
|
||||
T * pFirst;
|
||||
T * pLast;
|
||||
unsigned itemCount;
|
||||
void clear ();
|
||||
tsDLList ( const tsDLList & ); // not allowed
|
||||
const tsDLList <T> & operator = ( const tsDLList <T> & ); // not allowed
|
||||
};
|
||||
|
||||
//
|
||||
// class tsDLIterConst<T>
|
||||
//
|
||||
// bi-directional iterator for a const doubly linked list
|
||||
//
|
||||
template <class T>
|
||||
class tsDLIterConst {
|
||||
public:
|
||||
tsDLIterConst ();
|
||||
bool valid () const;
|
||||
bool operator == ( const tsDLIterConst<T> & rhs ) const;
|
||||
bool operator != ( const tsDLIterConst<T> & rhs ) const;
|
||||
tsDLIterConst<T> & operator = ( const tsDLIterConst<T> & );
|
||||
const T & operator * () const;
|
||||
const T * operator -> () const;
|
||||
tsDLIterConst<T> & operator ++ ();
|
||||
tsDLIterConst<T> operator ++ (int);
|
||||
tsDLIterConst<T> & operator -- ();
|
||||
tsDLIterConst<T> operator -- (int);
|
||||
const T * pointer () const;
|
||||
private:
|
||||
const T * pEntry;
|
||||
tsDLIterConst ( const T * pInitialEntry );
|
||||
friend class tsDLList <T>;
|
||||
};
|
||||
|
||||
//
|
||||
// class tsDLIter<T>
|
||||
//
|
||||
// bi-directional iterator for a doubly linked list
|
||||
//
|
||||
template <class T>
|
||||
class tsDLIter {
|
||||
public:
|
||||
tsDLIter ();
|
||||
bool valid () const;
|
||||
bool operator == ( const tsDLIter<T> & rhs ) const;
|
||||
bool operator != ( const tsDLIter<T> & rhs ) const;
|
||||
tsDLIter<T> & operator = ( const tsDLIter<T> & );
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
tsDLIter<T> & operator ++ ();
|
||||
tsDLIter<T> operator ++ ( int );
|
||||
tsDLIter<T> & operator -- ();
|
||||
tsDLIter<T> operator -- ( int );
|
||||
T * pointer () const;
|
||||
private:
|
||||
T * pEntry;
|
||||
tsDLIter ( T *pInitialEntry );
|
||||
friend class tsDLList <T>;
|
||||
};
|
||||
|
||||
///////////////////////////////////
|
||||
// tsDLNode<T> member functions
|
||||
///////////////////////////////////
|
||||
|
||||
//
|
||||
// tsDLNode<T>::tsDLNode ()
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLNode<T>::tsDLNode() : pNext(0), pPrev(0) {}
|
||||
|
||||
template <class T>
|
||||
inline tsDLNode<T>::tsDLNode ( const tsDLNode<T> & ) :
|
||||
pNext (0), pPrev(0) {}
|
||||
|
||||
//
|
||||
// tsDLNode<T>::operator = ()
|
||||
//
|
||||
// when someone tries to copy another node into a node
|
||||
// do _not_ change the node pointers
|
||||
//
|
||||
template <class T>
|
||||
inline const tsDLNode<T> & tsDLNode<T>::operator = ( const tsDLNode<T> & )
|
||||
{
|
||||
return * this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// tsDLList<T> member functions
|
||||
//////////////////////////////////////
|
||||
|
||||
//
|
||||
// tsDLList<T>::tsDLList ()
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLList<T>::tsDLList ()
|
||||
{
|
||||
this->clear ();
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::count ()
|
||||
//
|
||||
// (returns the number of items on the list)
|
||||
//
|
||||
template <class T>
|
||||
inline unsigned tsDLList<T>::count () const
|
||||
{
|
||||
return this->itemCount;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::first ()
|
||||
//
|
||||
template <class T>
|
||||
inline T * tsDLList<T>::first (void) const
|
||||
{
|
||||
return this->pFirst;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::last ()
|
||||
//
|
||||
template <class T>
|
||||
inline T *tsDLList<T>::last (void) const
|
||||
{
|
||||
return this->pLast;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::clear ()
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::clear ()
|
||||
{
|
||||
this->pFirst = 0;
|
||||
this->pLast = 0;
|
||||
this->itemCount = 0u;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::remove ()
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::remove ( T &item )
|
||||
{
|
||||
tsDLNode<T> &theNode = item;
|
||||
|
||||
if ( this->pLast == &item ) {
|
||||
this->pLast = theNode.pPrev;
|
||||
}
|
||||
else {
|
||||
tsDLNode<T> &nextNode = *theNode.pNext;
|
||||
nextNode.pPrev = theNode.pPrev;
|
||||
}
|
||||
|
||||
if ( this->pFirst == &item ) {
|
||||
this->pFirst = theNode.pNext;
|
||||
}
|
||||
else {
|
||||
tsDLNode<T> &prevNode = *theNode.pPrev;
|
||||
prevNode.pNext = theNode.pNext;
|
||||
}
|
||||
|
||||
this->itemCount--;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::removeAll ()
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::removeAll (
|
||||
tsDLList <T> & destination )
|
||||
{
|
||||
destination.pFirst = this->pFirst;
|
||||
destination.pLast = this->pLast;
|
||||
destination.itemCount = this->itemCount;
|
||||
this->pFirst = 0;
|
||||
this->pLast = 0;
|
||||
this->itemCount = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::get ()
|
||||
//
|
||||
template <class T>
|
||||
inline T * tsDLList<T>::get()
|
||||
{
|
||||
T *pItem = this->pFirst;
|
||||
|
||||
if ( pItem ) {
|
||||
this->remove ( *pItem );
|
||||
}
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::pop ()
|
||||
//
|
||||
// (returns the first item on the list)
|
||||
template <class T>
|
||||
inline T * tsDLList<T>::pop ()
|
||||
{
|
||||
return this->get ();
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::add ()
|
||||
//
|
||||
// adds addList to the end of the list
|
||||
// (and removes all items from addList)
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::add ( tsDLList<T> &addList )
|
||||
{
|
||||
if ( addList.itemCount != 0u ) {
|
||||
if ( this->itemCount == 0u ) {
|
||||
this->pFirst = addList.pFirst;
|
||||
}
|
||||
else {
|
||||
tsDLNode<T> *pLastNode = this->pLast;
|
||||
tsDLNode<T> *pAddListFirstNode = addList.pFirst;
|
||||
pLastNode->pNext = addList.pFirst;
|
||||
pAddListFirstNode->pPrev = addList.pLast;
|
||||
}
|
||||
this->pLast = addList.pLast;
|
||||
this->itemCount += addList.itemCount;
|
||||
addList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::add ()
|
||||
//
|
||||
// add an item to the end of the list
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::add (T &item)
|
||||
{
|
||||
tsDLNode<T> &theNode = item;
|
||||
|
||||
theNode.pNext = 0;
|
||||
theNode.pPrev = this->pLast;
|
||||
|
||||
if ( this->itemCount ) {
|
||||
tsDLNode<T> &lastNode = *this->pLast;
|
||||
lastNode.pNext = &item;
|
||||
}
|
||||
else {
|
||||
this->pFirst = &item;
|
||||
}
|
||||
|
||||
this->pLast = &item;
|
||||
|
||||
this->itemCount++;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::insertAfter ()
|
||||
//
|
||||
// place item in the list immediately after itemBefore
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::insertAfter (T &item, T &itemBefore)
|
||||
{
|
||||
tsDLNode<T> &nodeItem = item;
|
||||
tsDLNode<T> &nodeBefore = itemBefore;
|
||||
|
||||
nodeItem.pPrev = &itemBefore;
|
||||
nodeItem.pNext = nodeBefore.pNext;
|
||||
nodeBefore.pNext = &item;
|
||||
|
||||
if (nodeItem.pNext) {
|
||||
tsDLNode<T> *pNextNode = nodeItem.pNext;
|
||||
pNextNode->pPrev = &item;
|
||||
}
|
||||
else {
|
||||
this->pLast = &item;
|
||||
}
|
||||
|
||||
this->itemCount++;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::insertBefore ()
|
||||
//
|
||||
// place item in the list immediately before itemAfter
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::insertBefore (T &item, T &itemAfter)
|
||||
{
|
||||
tsDLNode<T> &node = item;
|
||||
tsDLNode<T> &nodeAfter = itemAfter;
|
||||
|
||||
node.pNext = &itemAfter;
|
||||
node.pPrev = nodeAfter.pPrev;
|
||||
nodeAfter.pPrev = &item;
|
||||
|
||||
if (node.pPrev) {
|
||||
tsDLNode<T> &prevNode = *node.pPrev;
|
||||
prevNode.pNext = &item;
|
||||
}
|
||||
else {
|
||||
this->pFirst = &item;
|
||||
}
|
||||
|
||||
this->itemCount++;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::push ()
|
||||
//
|
||||
// adds pushList to the beginning of the list
|
||||
// (and removes all items from pushList)
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::push ( tsDLList<T> & pushList )
|
||||
{
|
||||
if ( pushList.itemCount != 0u ) {
|
||||
if ( this->itemCount ) {
|
||||
tsDLNode<T> * pFirstNode = this->pFirst;
|
||||
tsDLNode<T> * pAddListLastNode = pushList.pLast;
|
||||
pFirstNode->pPrev = pushList.pLast;
|
||||
pAddListLastNode->pNext = this->pFirst;
|
||||
}
|
||||
else {
|
||||
this->pLast = pushList.pLast;
|
||||
}
|
||||
this->pFirst = pushList.pFirst;
|
||||
this->itemCount += pushList.itemCount;
|
||||
pushList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::push ()
|
||||
//
|
||||
// add an item at the beginning of the list
|
||||
//
|
||||
template <class T>
|
||||
inline void tsDLList<T>::push (T &item)
|
||||
{
|
||||
tsDLNode<T> &theNode = item;
|
||||
theNode.pPrev = 0;
|
||||
theNode.pNext = this->pFirst;
|
||||
|
||||
if ( this->itemCount ) {
|
||||
tsDLNode<T> *pFirstNode = this->pFirst;
|
||||
pFirstNode->pPrev = & item;
|
||||
}
|
||||
else {
|
||||
this->pLast = & item;
|
||||
}
|
||||
|
||||
this->pFirst = &item;
|
||||
|
||||
this->itemCount++;
|
||||
}
|
||||
|
||||
//
|
||||
// tsDLList<T>::find ()
|
||||
// returns -1 if the item isnt on the list
|
||||
// and the node number (beginning with zero if
|
||||
// it is)
|
||||
//
|
||||
template < class T >
|
||||
int tsDLList < T > :: find ( const T &item ) const
|
||||
{
|
||||
tsDLIterConst < T > thisItem ( &item );
|
||||
tsDLIterConst < T > iter ( this->first () );
|
||||
int itemNo = 0;
|
||||
|
||||
while ( iter.valid () ) {
|
||||
if ( iter == thisItem ) {
|
||||
return itemNo;
|
||||
}
|
||||
itemNo++;
|
||||
iter++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIterConst <T> tsDLList < T > :: firstIter () const
|
||||
{
|
||||
return tsDLIterConst < T > ( this->pFirst );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIter <T> tsDLList < T > :: firstIter ()
|
||||
{
|
||||
return tsDLIter < T > ( this->pFirst );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIterConst <T> tsDLList < T > :: lastIter () const
|
||||
{
|
||||
return tsDLIterConst < T > ( this->pLast );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIter <T> tsDLList < T > :: lastIter ()
|
||||
{
|
||||
return tsDLIter < T > ( this->pLast );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIterConst <T> tsDLList < T > :: invalidConstIter ()
|
||||
{
|
||||
return tsDLIterConst < T > ( 0 );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsDLIter <T> tsDLList < T > :: invalidIter ()
|
||||
{
|
||||
return tsDLIter < T > ( 0 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// tsDLIterConst<T> member functions
|
||||
//////////////////////////////////////////
|
||||
template <class T>
|
||||
inline tsDLIterConst<T>::tsDLIterConst ( const T *pInitialEntry ) :
|
||||
pEntry ( pInitialEntry ) {}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIterConst<T>::tsDLIterConst () :
|
||||
pEntry ( 0 ) {}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIterConst<T>::valid () const
|
||||
{
|
||||
return this->pEntry != 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIterConst<T>::operator == (const tsDLIterConst<T> &rhs) const
|
||||
{
|
||||
return this->pEntry == rhs.pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIterConst<T>::operator != (const tsDLIterConst<T> &rhs) const
|
||||
{
|
||||
return this->pEntry != rhs.pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIterConst<T> & tsDLIterConst<T>::operator = ( const tsDLIterConst<T> & rhs )
|
||||
{
|
||||
this->pEntry = rhs.pEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T & tsDLIterConst<T>::operator * () const
|
||||
{
|
||||
return *this->pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T * tsDLIterConst<T>::operator -> () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
//
|
||||
// prefix ++
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLIterConst<T> & tsDLIterConst<T>::operator ++ ()
|
||||
{
|
||||
const tsDLNode<T> &node = *this->pEntry;
|
||||
this->pEntry = node.pNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// postfix ++
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLIterConst<T> tsDLIterConst<T>::operator ++ (int)
|
||||
{
|
||||
const tsDLIterConst<T> tmp = *this;
|
||||
const tsDLNode<T> &node = *this->pEntry;
|
||||
this->pEntry = node.pNext;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//
|
||||
// prefix --
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLIterConst<T> & tsDLIterConst<T>::operator -- ()
|
||||
{
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pPrev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// postfix --
|
||||
//
|
||||
template <class T>
|
||||
inline tsDLIterConst<T> tsDLIterConst<T>::operator -- (int)
|
||||
{
|
||||
const tsDLIterConst<T> tmp = *this;
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pPrev;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T * tsDLIterConst<T>::pointer () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// tsDLIter<T> member functions
|
||||
//////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T>::tsDLIter ( T * pInitialEntry ) :
|
||||
pEntry ( pInitialEntry ) {}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T>::tsDLIter () :
|
||||
pEntry ( 0 ) {}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIter<T>::valid () const
|
||||
{
|
||||
return this->pEntry != 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIter<T>::operator == (const tsDLIter<T> &rhs) const
|
||||
{
|
||||
return this->pEntry == rhs.pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool tsDLIter<T>::operator != (const tsDLIter<T> &rhs) const
|
||||
{
|
||||
return this->pEntry != rhs.pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T> & tsDLIter<T>::operator = ( const tsDLIter<T> & rhs )
|
||||
{
|
||||
this->pEntry = rhs.pEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T & tsDLIter<T>::operator * () const
|
||||
{
|
||||
return *this->pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T * tsDLIter<T>::operator -> () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T> & tsDLIter<T>::operator ++ () // prefix ++
|
||||
{
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T> tsDLIter<T>::operator ++ (int) // postfix ++
|
||||
{
|
||||
const tsDLIter<T> tmp = *this;
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pNext;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T> & tsDLIter<T>::operator -- () // prefix --
|
||||
{
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pPrev;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsDLIter<T> tsDLIter<T>::operator -- (int) // postfix --
|
||||
{
|
||||
const tsDLIter<T> tmp = *this;
|
||||
const tsDLNode<T> &entryNode = *this->pEntry;
|
||||
this->pEntry = entryNode.pPrev;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T * tsDLIter<T>::pointer () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
#endif // tsDLListH_include
|
||||
|
||||
191
modules/libcom/src/cxxTemplates/tsFreeList.h
Normal file
191
modules/libcom/src/cxxTemplates/tsFreeList.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef tsFreeList_h
|
||||
#define tsFreeList_h
|
||||
|
||||
/*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
//
|
||||
// TODO: this should allow free list chaining so that a free
|
||||
// list (in a different lock domain) is used to provide the
|
||||
// tsFreeListChunk.
|
||||
//
|
||||
|
||||
//
|
||||
// To allow your class to be allocated off of a free list
|
||||
// using the new operator:
|
||||
//
|
||||
// 1) add the following static, private free list data members
|
||||
// to your class
|
||||
//
|
||||
// static tsFreeList < class classXYZ > freeList;
|
||||
//
|
||||
// 2) add the following member functions to your class
|
||||
//
|
||||
// inline void * classXYZ::operator new ( size_t size )
|
||||
// {
|
||||
// return freeList.allocate ( size );
|
||||
// }
|
||||
//
|
||||
// inline void classXYZ::operator delete ( void *pCadaver, size_t size )
|
||||
// {
|
||||
// freeList.release ( pCadaver, size );
|
||||
// }
|
||||
//
|
||||
// NOTES:
|
||||
//
|
||||
// 1) A NOOP mutex class may be specified if mutual exclusion isnt required
|
||||
//
|
||||
// 2) If you wish to force use of the new operator, then declare your class's
|
||||
// destructor as a protected member function.
|
||||
//
|
||||
// 3) Setting N to zero causes the free list to be bypassed
|
||||
//
|
||||
|
||||
#ifdef EPICS_FREELIST_DEBUG
|
||||
# define tsFreeListDebugBypass 1
|
||||
# define tsFreeListMemSetNew(P,SIZE) memset ( (P), 0xaa, (SIZE) )
|
||||
# define tsFreeListMemSetDelete(P,SIZE) memset ( (P), 0xdd, (SIZE) )
|
||||
#else
|
||||
# define tsFreeListDebugBypass 0
|
||||
# define tsFreeListMemSetNew(P,SIZE)
|
||||
# define tsFreeListMemSetDelete(P,SIZE)
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
#include "string.h"
|
||||
|
||||
#include "compilerDependencies.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
|
||||
// ms visual studio 6.0 and before incorrectly
|
||||
// warn about a missing delete operator if only the
|
||||
// newly preferred delete operator with a size argument
|
||||
// is present
|
||||
#if defined ( _MSC_VER ) && _MSC_VER <= 1200
|
||||
# pragma warning ( disable : 4291 )
|
||||
#endif
|
||||
|
||||
template < class T > union tsFreeListItem;
|
||||
template < class T, unsigned N> struct tsFreeListChunk;
|
||||
|
||||
template < class T, unsigned N = 0x400,
|
||||
class MUTEX = epicsMutex >
|
||||
class tsFreeList {
|
||||
public:
|
||||
tsFreeList ();
|
||||
~tsFreeList ();
|
||||
void * allocate ( size_t size );
|
||||
void release ( void * p );
|
||||
void release ( void * p, size_t size );
|
||||
private:
|
||||
MUTEX mutex;
|
||||
tsFreeListItem < T > * pFreeList;
|
||||
tsFreeListChunk < T, N > * pChunkList;
|
||||
void * allocateFromNewChunk ();
|
||||
};
|
||||
|
||||
template < class T >
|
||||
union tsFreeListItem {
|
||||
public:
|
||||
char pad [ sizeof ( T ) ];
|
||||
tsFreeListItem < T > * pNext;
|
||||
};
|
||||
|
||||
template < class T, unsigned N = 0x400 >
|
||||
struct tsFreeListChunk {
|
||||
tsFreeListItem < T > items [N];
|
||||
tsFreeListChunk < T, N > * pNext;
|
||||
};
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline tsFreeList < T, N, MUTEX > :: tsFreeList () :
|
||||
pFreeList ( 0 ), pChunkList ( 0 ) {}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
tsFreeList < T, N, MUTEX > :: ~tsFreeList ()
|
||||
{
|
||||
while ( tsFreeListChunk < T, N > *pChunk = this->pChunkList ) {
|
||||
this->pChunkList = this->pChunkList->pNext;
|
||||
delete pChunk;
|
||||
}
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
void * tsFreeList < T, N, MUTEX >::allocate ( size_t size )
|
||||
{
|
||||
if ( size != sizeof ( T ) || N == 0u || tsFreeListDebugBypass ) {
|
||||
void * p = ::operator new ( size );
|
||||
tsFreeListMemSetNew ( p, size );
|
||||
return p;
|
||||
}
|
||||
|
||||
epicsGuard < MUTEX > guard ( this->mutex );
|
||||
|
||||
tsFreeListItem < T > * p = this->pFreeList;
|
||||
if ( p ) {
|
||||
this->pFreeList = p->pNext;
|
||||
return static_cast < void * > ( p );
|
||||
}
|
||||
return this->allocateFromNewChunk ();
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
void * tsFreeList < T, N, MUTEX >::allocateFromNewChunk ()
|
||||
{
|
||||
tsFreeListChunk < T, N > * pChunk =
|
||||
new tsFreeListChunk < T, N >;
|
||||
|
||||
for ( unsigned i=1u; i < N-1; i++ ) {
|
||||
pChunk->items[i].pNext = &pChunk->items[i+1];
|
||||
}
|
||||
pChunk->items[N-1].pNext = 0;
|
||||
if ( N > 1 ) {
|
||||
this->pFreeList = &pChunk->items[1u];
|
||||
}
|
||||
pChunk->pNext = this->pChunkList;
|
||||
this->pChunkList = pChunk;
|
||||
|
||||
return static_cast <void *> ( &pChunk->items[0] );
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
void tsFreeList < T, N, MUTEX >::release ( void * pCadaver, size_t size )
|
||||
{
|
||||
if ( size != sizeof ( T ) ) {
|
||||
tsFreeListMemSetDelete ( pCadaver, size );
|
||||
::operator delete ( pCadaver );
|
||||
}
|
||||
else {
|
||||
this->release ( pCadaver );
|
||||
}
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
void tsFreeList < T, N, MUTEX >::release ( void * pCadaver )
|
||||
{
|
||||
if ( N == 0u || tsFreeListDebugBypass ) {
|
||||
tsFreeListMemSetDelete ( pCadaver, sizeof ( T ) );
|
||||
::operator delete ( pCadaver );
|
||||
}
|
||||
else if ( pCadaver ) {
|
||||
epicsGuard < MUTEX > guard ( this->mutex );
|
||||
tsFreeListItem < T > * p =
|
||||
static_cast < tsFreeListItem < T > * > ( pCadaver );
|
||||
p->pNext = this->pFreeList;
|
||||
this->pFreeList = p;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // tsFreeList_h
|
||||
31
modules/libcom/src/cxxTemplates/tsMinMax.h
Normal file
31
modules/libcom/src/cxxTemplates/tsMinMax.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
//
|
||||
// simple type safe inline template functions to replace
|
||||
// the min() and max() macros
|
||||
//
|
||||
|
||||
#ifndef tsMinMaxh
|
||||
#define tsMinMaxh
|
||||
|
||||
template <class T>
|
||||
inline const T & tsMax ( const T & a, const T & b )
|
||||
{
|
||||
return ( a > b ) ? a : b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T & tsMin ( const T & a, const T & b )
|
||||
{
|
||||
return ( a < b ) ? a : b;
|
||||
}
|
||||
|
||||
#endif // tsMinMaxh
|
||||
443
modules/libcom/src/cxxTemplates/tsSLList.h
Normal file
443
modules/libcom/src/cxxTemplates/tsSLList.h
Normal file
@@ -0,0 +1,443 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* type safe singly linked list templates
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef tsSLListh
|
||||
#define tsSLListh
|
||||
|
||||
#ifndef assert // allow use of epicsAssert.h
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
//
|
||||
// the hp compiler complains about parameterized friend
|
||||
// class that has not been declared without this?
|
||||
//
|
||||
template < class T > class tsSLList;
|
||||
template < class T > class tsSLIter;
|
||||
template < class T > class tsSLIterConst;
|
||||
|
||||
//
|
||||
// tsSLNode<T>
|
||||
// NOTE: class T must derive from tsSLNode<T>
|
||||
//
|
||||
template <class T>
|
||||
class tsSLNode {
|
||||
public:
|
||||
tsSLNode ();
|
||||
tsSLNode < T > & operator = ( const tsSLNode < T > & );
|
||||
private:
|
||||
void removeNextItem (); // removes the item after this node
|
||||
T *pNext;
|
||||
tsSLNode ( const tsSLNode < T > & );
|
||||
friend class tsSLList < T >;
|
||||
friend class tsSLIter < T >;
|
||||
friend class tsSLIterConst < T >;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// tsSLList<T>
|
||||
// NOTE: class T must derive from tsSLNode<T>
|
||||
//
|
||||
template < class T >
|
||||
class tsSLList : public tsSLNode < T > {
|
||||
public:
|
||||
tsSLList (); // creates an empty list
|
||||
tsSLList ( tsSLList & );
|
||||
void insert ( T &item, tsSLNode < T > &itemBefore ); // insert after item before
|
||||
void add ( T &item ); // add to the beginning of the list
|
||||
T * get (); // remove from the beginning of the list
|
||||
T * pop (); // same as get
|
||||
void push ( T &item ); // same as add
|
||||
T * first () const;
|
||||
void remove ( T &itemBefore );
|
||||
tsSLIterConst <T> firstIter () const;
|
||||
tsSLIter <T> firstIter ();
|
||||
static tsSLIterConst <T> invalidConstIter ();
|
||||
static tsSLIter <T> invalidIter ();
|
||||
private:
|
||||
const tsSLList < T > & operator = ( const tsSLList < T > & );
|
||||
};
|
||||
|
||||
//
|
||||
// tsSLIterConst<T>
|
||||
//
|
||||
template < class T >
|
||||
class tsSLIterConst {
|
||||
public:
|
||||
tsSLIterConst ();
|
||||
bool valid () const;
|
||||
bool operator == (const tsSLIterConst<T> &rhs) const;
|
||||
bool operator != (const tsSLIterConst<T> &rhs) const;
|
||||
tsSLIterConst<T> & operator = (const tsSLIterConst<T> &);
|
||||
const T & operator * () const;
|
||||
const T * operator -> () const;
|
||||
tsSLIterConst<T> & operator ++ ();
|
||||
tsSLIterConst<T> operator ++ (int);
|
||||
const T * pointer () const;
|
||||
protected:
|
||||
const T * pEntry;
|
||||
tsSLIterConst ( const T *pInitialEntry );
|
||||
friend class tsSLList < T >;
|
||||
};
|
||||
|
||||
//
|
||||
// tsSLIter<T>
|
||||
//
|
||||
template < class T >
|
||||
class tsSLIter {
|
||||
public:
|
||||
tsSLIter ();
|
||||
bool valid () const;
|
||||
bool operator == (const tsSLIter<T> &rhs) const;
|
||||
bool operator != (const tsSLIter<T> &rhs) const;
|
||||
tsSLIter<T> & operator = (const tsSLIter<T> &);
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
tsSLIter <T> & operator ++ ();
|
||||
tsSLIter <T> operator ++ (int);
|
||||
T * pointer () const;
|
||||
private:
|
||||
T *pEntry;
|
||||
tsSLIter ( T *pInitialEntry );
|
||||
friend class tsSLList < T >;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// tsSLNode<T> inline member functions
|
||||
//
|
||||
//////////////////////////////////////////
|
||||
|
||||
//
|
||||
// tsSLNode<T>::tsSLNode ()
|
||||
//
|
||||
template < class T >
|
||||
inline tsSLNode < T > :: tsSLNode () : pNext ( 0 ) {}
|
||||
|
||||
//
|
||||
// tsSLNode<T>::tsSLNode ( const tsSLNode < T > & )
|
||||
// private - not to be used - implemented to eliminate warnings
|
||||
//
|
||||
template < class T >
|
||||
inline tsSLNode < T > :: tsSLNode ( const tsSLNode < T > & )
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLNode<T>::operator =
|
||||
//
|
||||
// when someone copies into a class deriving from this
|
||||
// do _not_ change the node pointers
|
||||
//
|
||||
template < class T >
|
||||
inline tsSLNode < T > & tsSLNode < T >::operator =
|
||||
( const tsSLNode < T > & )
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// removeNextItem ()
|
||||
//
|
||||
// removes the item after this node
|
||||
//
|
||||
template <class T>
|
||||
inline void tsSLNode<T>::removeNextItem ()
|
||||
{
|
||||
T *pItem = this->pNext;
|
||||
if ( pItem ) {
|
||||
tsSLNode < T > *pNode = pItem;
|
||||
this->pNext = pNode->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// tsSLList<T> inline member functions
|
||||
//
|
||||
//////////////////////////////////////////
|
||||
|
||||
//
|
||||
// tsSLList<T>::tsSLList()
|
||||
// create an empty list
|
||||
//
|
||||
template < class T >
|
||||
inline tsSLList < T > :: tsSLList ()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::tsSLList( tsSLList & )
|
||||
//
|
||||
template < class T >
|
||||
inline tsSLList < T > :: tsSLList ( tsSLList &listIn )
|
||||
{
|
||||
this->pNext = listIn.pNext;
|
||||
listIn.pNext = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::insert()
|
||||
// (itemBefore might be the list header object and therefore
|
||||
// will not always be of type T)
|
||||
//
|
||||
template < class T >
|
||||
inline void tsSLList < T > :: insert ( T &item, tsSLNode < T > &itemBefore )
|
||||
{
|
||||
tsSLNode < T > &node = item;
|
||||
node.pNext = itemBefore.pNext;
|
||||
itemBefore.pNext = &item;
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::add ()
|
||||
//
|
||||
template < class T >
|
||||
inline void tsSLList < T > :: add ( T &item )
|
||||
{
|
||||
this->insert ( item, *this );
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::get ()
|
||||
//
|
||||
template < class T >
|
||||
inline T * tsSLList < T > :: get ()
|
||||
{
|
||||
tsSLNode < T > *pThisNode = this;
|
||||
T *pItem = pThisNode->pNext;
|
||||
pThisNode->removeNextItem ();
|
||||
return pItem;
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::pop ()
|
||||
//
|
||||
template < class T >
|
||||
inline T * tsSLList < T > :: pop ()
|
||||
{
|
||||
return this->get ();
|
||||
}
|
||||
|
||||
//
|
||||
// tsSLList<T>::push ()
|
||||
//
|
||||
template <class T>
|
||||
inline void tsSLList < T > :: push ( T &item )
|
||||
{
|
||||
this->add (item);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T * tsSLList < T > :: first () const
|
||||
{
|
||||
const tsSLNode < T > *pThisNode = this;
|
||||
return pThisNode->pNext;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void tsSLList < T > :: remove ( T &itemBefore )
|
||||
{
|
||||
tsSLNode < T > *pBeforeNode = &itemBefore;
|
||||
tsSLNode < T > *pAfterNode = pBeforeNode->pNext;
|
||||
pBeforeNode->pNext = pAfterNode->pNext;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsSLIterConst <T> tsSLList < T > :: firstIter () const
|
||||
{
|
||||
const tsSLNode < T > *pThisNode = this;
|
||||
return tsSLIterConst <T> ( pThisNode->pNext );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsSLIter <T> tsSLList < T > :: firstIter ()
|
||||
{
|
||||
tsSLNode < T > *pThisNode = this;
|
||||
return tsSLIter <T> ( pThisNode->pNext );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsSLIterConst <T> tsSLList < T > :: invalidConstIter ()
|
||||
{
|
||||
return tsSLIterConst <T> ( 0 );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline tsSLIter <T> tsSLList < T > :: invalidIter ()
|
||||
{
|
||||
return tsSLIter <T> ( 0 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// tsSLIterConst<T> inline member functions
|
||||
//
|
||||
//////////////////////////////////////////
|
||||
|
||||
template < class T >
|
||||
inline tsSLIterConst<T>::tsSLIterConst ( const T *pInitialEntry ) :
|
||||
pEntry ( pInitialEntry )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIterConst<T>::tsSLIterConst () :
|
||||
pEntry ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIterConst<T>::valid () const
|
||||
{
|
||||
return this->pEntry != 0;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIterConst<T>::operator == ( const tsSLIterConst<T> &rhs ) const
|
||||
{
|
||||
return this->pEntry == rhs.pConstEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIterConst<T>::operator != (const tsSLIterConst<T> &rhs) const
|
||||
{
|
||||
return this->pEntry != rhs.pConstEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIterConst<T> & tsSLIterConst<T>::operator = ( const tsSLIterConst<T> & rhs )
|
||||
{
|
||||
this->pEntry = rhs.pEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline const T & tsSLIterConst<T>::operator * () const
|
||||
{
|
||||
return *this->pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline const T * tsSLIterConst<T>::operator -> () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIterConst<T> & tsSLIterConst<T>::operator ++ () // prefix ++
|
||||
{
|
||||
const tsSLNode < T > *pCurNode = this->pEntry;
|
||||
this->pEntry = pCurNode->pNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIterConst<T> tsSLIterConst<T>::operator ++ ( int ) // postfix ++
|
||||
{
|
||||
const tsSLIterConst<T> tmp = *this;
|
||||
const tsSLNode < T > *pCurNode = this->pEntry;
|
||||
this->pEntry = pCurNode->pNext;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T * tsSLIterConst < T > :: pointer () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
//
|
||||
// tsSLIter<T> inline member functions
|
||||
//
|
||||
//////////////////////////////////////////
|
||||
|
||||
template < class T >
|
||||
inline tsSLIter<T>::tsSLIter ( T *pInitialEntry ) :
|
||||
pEntry ( pInitialEntry )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIter<T>::tsSLIter () :
|
||||
pEntry ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIter<T>::valid () const
|
||||
{
|
||||
return this->pEntry != 0;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIter<T>::operator == ( const tsSLIter<T> &rhs ) const
|
||||
{
|
||||
return this->pEntry == rhs.pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool tsSLIter<T>::operator != ( const tsSLIter<T> &rhs ) const
|
||||
{
|
||||
return this->pEntry != rhs.pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIter<T> & tsSLIter<T>::operator = ( const tsSLIter<T> & rhs )
|
||||
{
|
||||
this->pEntry = rhs.pEntry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T & tsSLIter<T>::operator * () const
|
||||
{
|
||||
return *this->pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * tsSLIter<T>::operator -> () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIter<T> & tsSLIter<T>::operator ++ () // prefix ++
|
||||
{
|
||||
const tsSLNode < T > *pCurNode = this->pEntry;
|
||||
this->pEntry = pCurNode->pNext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline tsSLIter<T> tsSLIter<T>::operator ++ ( int ) // postfix ++
|
||||
{
|
||||
const tsSLIter<T> tmp = *this;
|
||||
const tsSLNode < T > *pCurNode = this->pEntry;
|
||||
this->pEntry = pCurNode->pNext;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T * tsSLIter < T > :: pointer () const
|
||||
{
|
||||
return this->pEntry;
|
||||
}
|
||||
|
||||
#endif // tsSLListh
|
||||
13
modules/libcom/src/dbmf/Makefile
Normal file
13
modules/libcom/src/dbmf/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/dbmf
|
||||
INC += dbmf.h
|
||||
Com_SRCS += dbmf.c
|
||||
|
||||
299
modules/libcom/src/dbmf/dbmf.c
Normal file
299
modules/libcom/src/dbmf/dbmf.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Jim Kowalkowski and Marty Kraimer
|
||||
* Date: 4/97
|
||||
*
|
||||
* Intended for applications that create and free requently
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "valgrind/valgrind.h"
|
||||
|
||||
#ifndef NVALGRIND
|
||||
/* buffer around allocations to detect out of bounds access */
|
||||
#define REDZONE sizeof(double)
|
||||
#else
|
||||
#define REDZONE 0
|
||||
#endif
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbmf.h"
|
||||
/*
|
||||
#define DBMF_FREELIST_DEBUG 1
|
||||
*/
|
||||
#ifndef DBMF_FREELIST_DEBUG
|
||||
|
||||
/*Default values for dblfInit */
|
||||
#define DBMF_SIZE 64
|
||||
#define DBMF_INITIAL_ITEMS 10
|
||||
|
||||
typedef struct chunkNode {/*control block for each set of chunkItems*/
|
||||
ELLNODE node;
|
||||
void *pchunk;
|
||||
int nNotFree;
|
||||
}chunkNode;
|
||||
|
||||
typedef struct itemHeader{
|
||||
void *pnextFree;
|
||||
chunkNode *pchunkNode;
|
||||
}itemHeader;
|
||||
|
||||
typedef struct dbmfPrivate {
|
||||
ELLLIST chunkList;
|
||||
epicsMutexId lock;
|
||||
size_t size;
|
||||
size_t allocSize;
|
||||
int chunkItems;
|
||||
size_t chunkSize;
|
||||
int nAlloc;
|
||||
int nFree;
|
||||
int nGtSize;
|
||||
void *freeList;
|
||||
} dbmfPrivate;
|
||||
dbmfPrivate dbmfPvt;
|
||||
static dbmfPrivate *pdbmfPvt = NULL;
|
||||
int dbmfDebug=0;
|
||||
|
||||
int dbmfInit(size_t size, int chunkItems)
|
||||
{
|
||||
if(pdbmfPvt) {
|
||||
printf("dbmfInit: Already initialized\n");
|
||||
return(-1);
|
||||
}
|
||||
pdbmfPvt = &dbmfPvt;
|
||||
ellInit(&pdbmfPvt->chunkList);
|
||||
pdbmfPvt->lock = epicsMutexMustCreate();
|
||||
/*allign to at least a double*/
|
||||
pdbmfPvt->size = size + size%sizeof(double);
|
||||
/* layout is
|
||||
* | itemHeader | REDZONE | size | REDZONE |
|
||||
*/
|
||||
pdbmfPvt->allocSize = pdbmfPvt->size + sizeof(itemHeader) + 2*REDZONE;
|
||||
pdbmfPvt->chunkItems = chunkItems;
|
||||
pdbmfPvt->chunkSize = pdbmfPvt->allocSize * pdbmfPvt->chunkItems;
|
||||
pdbmfPvt->nAlloc = 0;
|
||||
pdbmfPvt->nFree = 0;
|
||||
pdbmfPvt->nGtSize = 0;
|
||||
pdbmfPvt->freeList = NULL;
|
||||
VALGRIND_CREATE_MEMPOOL(pdbmfPvt, REDZONE, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void* dbmfMalloc(size_t size)
|
||||
{
|
||||
void **pnextFree;
|
||||
void **pfreeList;
|
||||
char *pmem = NULL;
|
||||
chunkNode *pchunkNode;
|
||||
itemHeader *pitemHeader;
|
||||
|
||||
if(!pdbmfPvt) dbmfInit(DBMF_SIZE,DBMF_INITIAL_ITEMS);
|
||||
epicsMutexMustLock(pdbmfPvt->lock);
|
||||
pfreeList = &pdbmfPvt->freeList;
|
||||
if(*pfreeList == NULL) {
|
||||
int i;
|
||||
size_t nbytesTotal;
|
||||
|
||||
if(dbmfDebug) printf("dbmfMalloc allocating new storage\n");
|
||||
nbytesTotal = pdbmfPvt->chunkSize + sizeof(chunkNode);
|
||||
pmem = (char *)malloc(nbytesTotal);
|
||||
if(!pmem) {
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
cantProceed("dbmfMalloc malloc failed\n");
|
||||
return(NULL);
|
||||
}
|
||||
pchunkNode = (chunkNode *)(pmem + pdbmfPvt->chunkSize);
|
||||
pchunkNode->pchunk = pmem;
|
||||
pchunkNode->nNotFree=0;
|
||||
ellAdd(&pdbmfPvt->chunkList,&pchunkNode->node);
|
||||
for(i=0; i<pdbmfPvt->chunkItems; i++) {
|
||||
pitemHeader = (itemHeader *)pmem;
|
||||
pitemHeader->pchunkNode = pchunkNode;
|
||||
pnextFree = &pitemHeader->pnextFree;
|
||||
*pnextFree = *pfreeList; *pfreeList = (void *)pmem;
|
||||
pdbmfPvt->nFree++;
|
||||
pmem += pdbmfPvt->allocSize;
|
||||
}
|
||||
}
|
||||
if(size<=pdbmfPvt->size) {
|
||||
pnextFree = *pfreeList; *pfreeList = *pnextFree;
|
||||
pmem = (void *)pnextFree;
|
||||
pdbmfPvt->nAlloc++; pdbmfPvt->nFree--;
|
||||
pitemHeader = (itemHeader *)pnextFree;
|
||||
pitemHeader->pchunkNode->nNotFree += 1;
|
||||
} else {
|
||||
pmem = malloc(sizeof(itemHeader) + 2*REDZONE + size);
|
||||
if(!pmem) {
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
cantProceed("dbmfMalloc malloc failed\n");
|
||||
return(NULL);
|
||||
}
|
||||
pdbmfPvt->nAlloc++;
|
||||
pdbmfPvt->nGtSize++;
|
||||
pitemHeader = (itemHeader *)pmem;
|
||||
pitemHeader->pchunkNode = NULL; /* not part of free list */
|
||||
if(dbmfDebug) printf("dbmfMalloc: size %lu mem %p\n",
|
||||
(unsigned long)size,pmem);
|
||||
}
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
pmem += sizeof(itemHeader) + REDZONE;
|
||||
VALGRIND_MEMPOOL_ALLOC(pdbmfPvt, pmem, size);
|
||||
return((void *)pmem);
|
||||
}
|
||||
|
||||
char * dbmfStrdup(const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
|
||||
|
||||
return strcpy(buf, str);
|
||||
}
|
||||
|
||||
char * dbmfStrndup(const char *str, size_t len)
|
||||
{
|
||||
char *buf = dbmfMalloc(len + 1); /* FIXME Can return NULL */
|
||||
|
||||
buf[len] = '\0';
|
||||
return strncpy(buf, str, len);
|
||||
}
|
||||
|
||||
void dbmfFree(void* mem)
|
||||
{
|
||||
char *pmem = (char *)mem;
|
||||
chunkNode *pchunkNode;
|
||||
itemHeader *pitemHeader;
|
||||
|
||||
if(!mem) return;
|
||||
if(!pdbmfPvt) {
|
||||
printf("dbmfFree called but dbmfInit never called\n");
|
||||
return;
|
||||
}
|
||||
VALGRIND_MEMPOOL_FREE(pdbmfPvt, mem);
|
||||
pmem -= sizeof(itemHeader) + REDZONE;
|
||||
epicsMutexMustLock(pdbmfPvt->lock);
|
||||
pitemHeader = (itemHeader *)pmem;
|
||||
if(!pitemHeader->pchunkNode) {
|
||||
if(dbmfDebug) printf("dbmfGree: mem %p\n",pmem);
|
||||
free((void *)pmem); pdbmfPvt->nAlloc--;
|
||||
}else {
|
||||
void **pfreeList = &pdbmfPvt->freeList;
|
||||
void **pnextFree = &pitemHeader->pnextFree;
|
||||
|
||||
pchunkNode = pitemHeader->pchunkNode;
|
||||
pchunkNode->nNotFree--;
|
||||
*pnextFree = *pfreeList; *pfreeList = pnextFree;
|
||||
pdbmfPvt->nAlloc--; pdbmfPvt->nFree++;
|
||||
}
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
}
|
||||
|
||||
int dbmfShow(int level)
|
||||
{
|
||||
if(pdbmfPvt==NULL) {
|
||||
printf("Never initialized\n");
|
||||
return(0);
|
||||
}
|
||||
printf("size %lu allocSize %lu chunkItems %d ",
|
||||
(unsigned long)pdbmfPvt->size,
|
||||
(unsigned long)pdbmfPvt->allocSize,pdbmfPvt->chunkItems);
|
||||
printf("nAlloc %d nFree %d nChunks %d nGtSize %d\n",
|
||||
pdbmfPvt->nAlloc,pdbmfPvt->nFree,
|
||||
ellCount(&pdbmfPvt->chunkList),pdbmfPvt->nGtSize);
|
||||
if(level>0) {
|
||||
chunkNode *pchunkNode;
|
||||
|
||||
pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
|
||||
while(pchunkNode) {
|
||||
printf("pchunkNode %p nNotFree %d\n",
|
||||
(void*)pchunkNode,pchunkNode->nNotFree);
|
||||
pchunkNode = (chunkNode *)ellNext(&pchunkNode->node);
|
||||
}
|
||||
}
|
||||
if(level>1) {
|
||||
void **pnextFree;;
|
||||
|
||||
epicsMutexMustLock(pdbmfPvt->lock);
|
||||
pnextFree = (void**)pdbmfPvt->freeList;
|
||||
while(pnextFree) {
|
||||
printf("%p\n",*pnextFree);
|
||||
pnextFree = (void**)*pnextFree;
|
||||
}
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void dbmfFreeChunks(void)
|
||||
{
|
||||
chunkNode *pchunkNode;
|
||||
chunkNode *pnext;;
|
||||
|
||||
if(!pdbmfPvt) {
|
||||
printf("dbmfFreeChunks called but dbmfInit never called\n");
|
||||
return;
|
||||
}
|
||||
epicsMutexMustLock(pdbmfPvt->lock);
|
||||
if(pdbmfPvt->nFree
|
||||
!= (pdbmfPvt->chunkItems * ellCount(&pdbmfPvt->chunkList))) {
|
||||
printf("dbmfFinish: not all free\n");
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
return;
|
||||
}
|
||||
pchunkNode = (chunkNode *)ellFirst(&pdbmfPvt->chunkList);
|
||||
while(pchunkNode) {
|
||||
pnext = (chunkNode *)ellNext(&pchunkNode->node);
|
||||
ellDelete(&pdbmfPvt->chunkList,&pchunkNode->node);
|
||||
free(pchunkNode->pchunk);
|
||||
pchunkNode = pnext;
|
||||
}
|
||||
pdbmfPvt->nFree = 0; pdbmfPvt->freeList = NULL;
|
||||
epicsMutexUnlock(pdbmfPvt->lock);
|
||||
}
|
||||
|
||||
#else /* DBMF_FREELIST_DEBUG */
|
||||
|
||||
int dbmfInit(size_t size, int chunkItems)
|
||||
{ return 0; }
|
||||
|
||||
void* dbmfMalloc(size_t size)
|
||||
{ return malloc(size); }
|
||||
|
||||
char * dbmfStrdup(const char *str)
|
||||
{ return strdup((char*)str); }
|
||||
|
||||
void dbmfFree(void* mem)
|
||||
{ free(mem); }
|
||||
|
||||
int dbmfShow(int level)
|
||||
{ return 0; }
|
||||
|
||||
void dbmfFreeChunks(void) {}
|
||||
|
||||
#endif /* DBMF_FREELIST_DEBUG */
|
||||
|
||||
char * dbmfStrcat3(const char *lhs, const char *mid, const char *rhs)
|
||||
{
|
||||
size_t len = strlen(lhs) + strlen(mid) + strlen(rhs) + 1;
|
||||
char *buf = dbmfMalloc(len);
|
||||
strcpy(buf, lhs);
|
||||
strcat(buf, mid);
|
||||
strcat(buf, rhs);
|
||||
return buf;
|
||||
}
|
||||
|
||||
49
modules/libcom/src/dbmf/dbmf.h
Normal file
49
modules/libcom/src/dbmf/dbmf.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Jim Kowalkowski and Marty Kraimer
|
||||
* Date: 4/97
|
||||
*
|
||||
* A library to manage storage that is allocated and then freed.
|
||||
*/
|
||||
#ifndef DBMF_H
|
||||
#define DBMF_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc int dbmfInit(size_t size, int chunkItems);
|
||||
epicsShareFunc void * dbmfMalloc(size_t bytes);
|
||||
epicsShareFunc char * dbmfStrdup(const char *str);
|
||||
epicsShareFunc char * dbmfStrndup(const char *str, size_t len);
|
||||
epicsShareFunc char * dbmfStrcat3(const char *lhs, const char *mid,
|
||||
const char *rhs);
|
||||
epicsShareFunc void dbmfFree(void *bytes);
|
||||
epicsShareFunc void dbmfFreeChunks(void);
|
||||
epicsShareFunc int dbmfShow(int level);
|
||||
|
||||
/* Rules:
|
||||
* 1) Size is always made a multiple of 8.
|
||||
* 2) if dbmfInit is not called before one of the other routines then it
|
||||
* is automatically called with size=64 and chunkItems=10
|
||||
* 3) These routines should only be used to allocate storage that will
|
||||
* shortly thereafter be freed.
|
||||
* 4) dbmfFreeChunks can only free chunks that contain only free items
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
13
modules/libcom/src/ellLib/Makefile
Normal file
13
modules/libcom/src/ellLib/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/ellLib
|
||||
INC += ellLib.h
|
||||
Com_SRCS += ellLib.c
|
||||
Com_SRCS += ellSort.c
|
||||
331
modules/libcom/src/ellLib/ellLib.c
Normal file
331
modules/libcom/src/ellLib/ellLib.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: John Winans (ANL)
|
||||
* Date: 07-02-92
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "ellLib.h"
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function adds a node to the end of a linked list.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellAdd (ELLLIST *pList, ELLNODE *pNode)
|
||||
{
|
||||
pNode->next = NULL;
|
||||
pNode->previous = pList->node.previous;
|
||||
|
||||
if (pList->count)
|
||||
pList->node.previous->next = pNode;
|
||||
else
|
||||
pList->node.next = pNode;
|
||||
|
||||
pList->node.previous = pNode;
|
||||
pList->count++;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function concatinates the second linked list to the end of the first
|
||||
* list. The second list is left empty. Either list (or both) lists may
|
||||
* be empty at the begining of the operation.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList)
|
||||
{
|
||||
if (pAddList->count == 0)
|
||||
return; /* Add list is empty, nothing to add. */
|
||||
|
||||
if (pDstList->count == 0) {
|
||||
/* Destination list is empty... just transfer the add list over. */
|
||||
pDstList->node.next = pAddList->node.next;
|
||||
pDstList->node.previous = pAddList->node.previous;
|
||||
pDstList->count = pAddList->count;
|
||||
} else {
|
||||
/* Destination list not empty... append the add list. */
|
||||
pDstList->node.previous->next = pAddList->node.next;
|
||||
pAddList->node.next->previous = pDstList->node.previous;
|
||||
pDstList->node.previous = pAddList->node.previous;
|
||||
pDstList->count += pAddList->count;
|
||||
}
|
||||
|
||||
pAddList->count = 0;
|
||||
pAddList->node.next = NULL;
|
||||
pAddList->node.previous = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function deletes a specific node from a specified list;
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellDelete (ELLLIST *pList, ELLNODE *pNode)
|
||||
{
|
||||
if (pList->node.previous == pNode)
|
||||
pList->node.previous = pNode->previous;
|
||||
else
|
||||
pNode->next->previous = pNode->previous;
|
||||
|
||||
if (pList->node.next == pNode)
|
||||
pList->node.next = pNode->next;
|
||||
else
|
||||
pNode->previous->next = pNode->next;
|
||||
|
||||
pList->count--;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function extracts a sublist that starts with pStartNode and ends with
|
||||
* pEndNode from pSrcList and places it in pDstList.
|
||||
*
|
||||
* WRS is unclear as to what happens when pDstList is non-empty at the start
|
||||
* of the operation. We will place the extracted list at the END of pDstList
|
||||
* when it is non-empty.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellExtract (ELLLIST *pSrcList, ELLNODE *pStartNode, ELLNODE *pEndNode, ELLLIST *pDstList)
|
||||
{
|
||||
ELLNODE *pnode;
|
||||
int count;
|
||||
|
||||
/* Cut the list out of the source list (update count later) */
|
||||
if (pStartNode->previous != NULL)
|
||||
pStartNode->previous->next = pEndNode->next;
|
||||
else
|
||||
pSrcList->node.next = pEndNode->next;
|
||||
|
||||
if (pEndNode->next != NULL) {
|
||||
pEndNode->next->previous = pStartNode->previous;
|
||||
pEndNode->next = NULL;
|
||||
}
|
||||
else
|
||||
pSrcList->node.previous = pStartNode->previous;
|
||||
|
||||
/* Place the sublist into the destination list */
|
||||
pStartNode->previous = pDstList->node.previous;
|
||||
if (pDstList->count)
|
||||
pDstList->node.previous->next = pStartNode;
|
||||
else
|
||||
pDstList->node.next = pStartNode;
|
||||
|
||||
pDstList->node.previous = pEndNode;
|
||||
|
||||
/* Adjust the counts */
|
||||
pnode = pStartNode;
|
||||
count = 1;
|
||||
while(pnode != pEndNode)
|
||||
{
|
||||
pnode = pnode->next;
|
||||
count++;
|
||||
}
|
||||
pSrcList->count -= count;
|
||||
pDstList->count += count;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function returns the first node in the specified list. The node is
|
||||
* removed from the list. If the list is empty, NULL will be returned.
|
||||
*
|
||||
*****************************************************************************/
|
||||
ELLNODE * ellGet (ELLLIST *pList)
|
||||
{
|
||||
ELLNODE *pnode = pList->node.next;
|
||||
|
||||
if (pnode != NULL)
|
||||
ellDelete(pList, pnode);
|
||||
|
||||
return pnode;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function returns the last node in the specified list. The node is
|
||||
* removed from the list. If the list is empty, NULL will be returned.
|
||||
*
|
||||
*****************************************************************************/
|
||||
ELLNODE * ellPop (ELLLIST *pList)
|
||||
{
|
||||
ELLNODE *pnode = pList->node.previous;
|
||||
|
||||
if (pnode != NULL)
|
||||
ellDelete(pList, pnode);
|
||||
|
||||
return pnode;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function inserts the specified node pNode after pPrev in the list
|
||||
* plist. If pPrev is NULL, then pNode will be inserted at the head of the
|
||||
* list.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode)
|
||||
{
|
||||
if (pPrev != NULL) {
|
||||
pNode->previous = pPrev;
|
||||
pNode->next = pPrev->next;
|
||||
pPrev->next = pNode;
|
||||
} else {
|
||||
pNode->previous = NULL;
|
||||
pNode->next = plist->node.next;
|
||||
plist->node.next = pNode;
|
||||
}
|
||||
|
||||
if (pNode->next == NULL)
|
||||
plist->node.previous = pNode;
|
||||
else
|
||||
pNode->next->previous = pNode;
|
||||
|
||||
plist->count++;
|
||||
|
||||
return;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function returns the nodeNum'th element in pList. If there is no
|
||||
* nodeNum'th node in the list, NULL will be returned.
|
||||
*
|
||||
*****************************************************************************/
|
||||
ELLNODE * ellNth (ELLLIST *pList, int nodeNum)
|
||||
{
|
||||
ELLNODE *pnode;
|
||||
|
||||
if ((nodeNum < 1) || (pList->count == 0))
|
||||
return NULL;
|
||||
|
||||
if (nodeNum > pList->count/2) {
|
||||
if (nodeNum > pList->count)
|
||||
return NULL;
|
||||
|
||||
pnode = pList->node.previous;
|
||||
nodeNum = pList->count - nodeNum;
|
||||
while(nodeNum) {
|
||||
pnode = pnode->previous;
|
||||
nodeNum--;
|
||||
}
|
||||
return pnode;
|
||||
}
|
||||
|
||||
pnode = pList->node.next;
|
||||
while (--nodeNum > 0)
|
||||
pnode = pnode->next;
|
||||
|
||||
return pnode;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function returns the node, nStep nodes forward from pNode. If there is
|
||||
* no node that many steps from pNode, NULL will be returned.
|
||||
*
|
||||
*****************************************************************************/
|
||||
ELLNODE * ellNStep (ELLNODE *pNode, int nStep)
|
||||
{
|
||||
if (nStep > 0) {
|
||||
while ((pNode != NULL) && nStep) {
|
||||
pNode = pNode->next;
|
||||
nStep--;
|
||||
}
|
||||
} else {
|
||||
while ((pNode != NULL) && nStep) {
|
||||
pNode = pNode->previous;
|
||||
nStep++;
|
||||
}
|
||||
}
|
||||
return pNode;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function returns the node number of pNode within pList. If the node is
|
||||
* not in pList, -1 is returned. Note that the first node is 1.
|
||||
*
|
||||
*****************************************************************************/
|
||||
int ellFind (ELLLIST *pList, ELLNODE *pNode)
|
||||
{
|
||||
ELLNODE *got = pList->node.next;
|
||||
int count = 1;
|
||||
|
||||
while ((got != pNode) && (got != NULL)) {
|
||||
got = got->next;
|
||||
count++;
|
||||
}
|
||||
if (got == NULL)
|
||||
return -1;
|
||||
|
||||
return count;
|
||||
}
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function frees the nodes in a list. It makes the list into an empty
|
||||
* list, and calls freeFunc() for all the nodes that are (were) in that list.
|
||||
*
|
||||
* NOTE: the nodes in the list are free()'d on the assumption that the node
|
||||
* structures were malloc()'d one-at-a-time and that the ELLNODE structure is
|
||||
* the first member of the parent structure.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc)
|
||||
{
|
||||
ELLNODE *nnode = pList->node.next;
|
||||
ELLNODE *pnode;
|
||||
|
||||
while (nnode != NULL)
|
||||
{
|
||||
pnode = nnode;
|
||||
nnode = nnode->next;
|
||||
freeFunc(pnode);
|
||||
}
|
||||
pList->node.next = NULL;
|
||||
pList->node.previous = NULL;
|
||||
pList->count = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* This function verifies that the list is consistent.
|
||||
* joh 12-12-97
|
||||
*
|
||||
*****************************************************************************/
|
||||
void ellVerify (ELLLIST *pList)
|
||||
{
|
||||
ELLNODE *pNode;
|
||||
ELLNODE *pNext;
|
||||
int count = 0;
|
||||
|
||||
assert (pList);
|
||||
|
||||
pNode = ellFirst(pList);
|
||||
if (pNode) {
|
||||
assert (ellPrevious(pNode) == NULL);
|
||||
while (1) {
|
||||
count++;
|
||||
pNext = ellNext(pNode);
|
||||
if (pNext) {
|
||||
assert (ellPrevious(pNext) == pNode);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
pNode = pNext;
|
||||
}
|
||||
assert (ellNext(pNode) == NULL);
|
||||
}
|
||||
|
||||
assert (pNode == ellLast(pList));
|
||||
assert (count == ellCount(pList));
|
||||
}
|
||||
68
modules/libcom/src/ellLib/ellLib.h
Normal file
68
modules/libcom/src/ellLib/ellLib.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: John Winans (ANL)
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
*/
|
||||
#ifndef INC_ellLib_H
|
||||
#define INC_ellLib_H
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ELLNODE {
|
||||
struct ELLNODE *next;
|
||||
struct ELLNODE *previous;
|
||||
} ELLNODE;
|
||||
|
||||
#define ELLNODE_INIT {NULL, NULL}
|
||||
|
||||
typedef struct ELLLIST {
|
||||
ELLNODE node;
|
||||
int count;
|
||||
} ELLLIST;
|
||||
|
||||
#define ELLLIST_INIT {ELLNODE_INIT, 0}
|
||||
|
||||
typedef void (*FREEFUNC)(void *);
|
||||
|
||||
#define ellInit(PLIST) {\
|
||||
(PLIST)->node.next = (PLIST)->node.previous = NULL;\
|
||||
(PLIST)->count = 0;\
|
||||
}
|
||||
#define ellCount(PLIST) ((PLIST)->count)
|
||||
#define ellFirst(PLIST) ((PLIST)->node.next)
|
||||
#define ellLast(PLIST) ((PLIST)->node.previous)
|
||||
#define ellNext(PNODE) ((PNODE)->next)
|
||||
#define ellPrevious(PNODE) ((PNODE)->previous)
|
||||
#define ellFree(PLIST) ellFree2(PLIST, free)
|
||||
|
||||
epicsShareFunc void ellAdd (ELLLIST *pList, ELLNODE *pNode);
|
||||
epicsShareFunc void ellConcat (ELLLIST *pDstList, ELLLIST *pAddList);
|
||||
epicsShareFunc void ellDelete (ELLLIST *pList, ELLNODE *pNode);
|
||||
epicsShareFunc void ellExtract (ELLLIST *pSrcList, ELLNODE *pStartNode, ELLNODE *pEndNode, ELLLIST *pDstList);
|
||||
epicsShareFunc ELLNODE * ellGet (ELLLIST *pList);
|
||||
epicsShareFunc ELLNODE * ellPop (ELLLIST *pList);
|
||||
epicsShareFunc void ellInsert (ELLLIST *plist, ELLNODE *pPrev, ELLNODE *pNode);
|
||||
epicsShareFunc ELLNODE * ellNth (ELLLIST *pList, int nodeNum);
|
||||
epicsShareFunc ELLNODE * ellNStep (ELLNODE *pNode, int nStep);
|
||||
epicsShareFunc int ellFind (ELLLIST *pList, ELLNODE *pNode);
|
||||
typedef int (*pListCmp)(const ELLNODE* A, const ELLNODE* B);
|
||||
epicsShareFunc void ellSortStable(ELLLIST *pList, pListCmp);
|
||||
epicsShareFunc void ellFree2 (ELLLIST *pList, FREEFUNC freeFunc);
|
||||
epicsShareFunc void ellVerify (ELLLIST *pList);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_ellLib_H */
|
||||
83
modules/libcom/src/ellLib/ellSort.c
Normal file
83
modules/libcom/src/ellLib/ellSort.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 Brookhaven Science Assoc., as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2016 Michael Davidsaver
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Use of mergesort algorithm based on analysis by
|
||||
* http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "ellLib.h"
|
||||
|
||||
static void ellMoveN(ELLLIST* pTo, ELLLIST* pFrom, int count )
|
||||
{
|
||||
for(;count && ellCount(pFrom); count--) {
|
||||
ELLNODE *node = ellGet(pFrom);
|
||||
ellAdd(pTo, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Stable (MergeSort) to given list.
|
||||
* The comparison function cmp(A,B) is expected
|
||||
* to return -1 for A<B, 0 for A==B, and 1 for A>B.
|
||||
*/
|
||||
void ellSortStable(ELLLIST *pList, pListCmp cmp)
|
||||
{
|
||||
ELLLIST INP, P, Q;
|
||||
size_t insize = 1; /* initial sub-list size */
|
||||
if(ellCount(pList)<=1)
|
||||
return;
|
||||
|
||||
ellInit(&INP);
|
||||
ellInit(&P);
|
||||
ellInit(&Q);
|
||||
|
||||
/* Process is to iteratively sort
|
||||
* a sequence of sub-lists of size 'insize'
|
||||
*/
|
||||
|
||||
while(insize < ellCount(pList)) {
|
||||
|
||||
assert(ellCount(&INP)==0);
|
||||
|
||||
/* shift previous results to inputs */
|
||||
ellConcat(&INP, pList);
|
||||
|
||||
while(ellCount(&INP))
|
||||
{
|
||||
ELLNODE *p, *q;
|
||||
|
||||
/* Pull out the next pair of sub-lists */
|
||||
ellMoveN(&Q, &INP, insize);
|
||||
ellMoveN(&P, &INP, insize);
|
||||
|
||||
/* merge these sub-lists */
|
||||
while((p=ellFirst(&P)) && (q=ellFirst(&Q)))
|
||||
{
|
||||
if((*cmp)(p,q) < 0) {
|
||||
ellAdd(pList, ellGet(&P));
|
||||
} else {
|
||||
ellAdd(pList, ellGet(&Q));
|
||||
}
|
||||
}
|
||||
|
||||
/* concatenate any remaining to result */
|
||||
if(ellFirst(&P))
|
||||
ellConcat(pList, &P);
|
||||
else if(ellFirst(&Q))
|
||||
ellConcat(pList, &Q);
|
||||
|
||||
assert(!ellFirst(&P) && !ellFirst(&Q));
|
||||
}
|
||||
|
||||
insize *= 2;
|
||||
}
|
||||
|
||||
}
|
||||
22
modules/libcom/src/env/Makefile
vendored
Normal file
22
modules/libcom/src/env/Makefile
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/env
|
||||
|
||||
vpath %.pl $(USR_VPATH) $(SRC_DIRS)
|
||||
|
||||
PERL_SCRIPTS += bldEnvData.pl
|
||||
PERL_SCRIPTS += libcomModuleDirs.pm
|
||||
|
||||
INC += envDefs.h
|
||||
|
||||
Com_SRCS += envSubr.c
|
||||
Com_SRCS += envData.c
|
||||
|
||||
CLEANS += envData.c
|
||||
15
modules/libcom/src/env/RULES
vendored
Normal file
15
modules/libcom/src/env/RULES
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
envData.c: $(LIBCOM)/env/envDefs.h \
|
||||
$(INSTALL_HOST_BIN)/bldEnvData.pl $(INSTALL_HOST_BIN)/libcomModuleDirs.pm \
|
||||
$(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV \
|
||||
$(wildcard $(CONFIG)/os/CONFIG_SITE_ENV.$(T_A))
|
||||
$(PERL) $(INSTALL_HOST_BIN)/bldEnvData.pl $(QUIET_FLAG) -t $(T_A) \
|
||||
-c $(CMPLR_CLASS) -s $(OS_CLASS) $(CONFIG)
|
||||
141
modules/libcom/src/env/bldEnvData.pl
vendored
Normal file
141
modules/libcom/src/env/bldEnvData.pl
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env perl
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# Author: Kay-Uwe Kasemir
|
||||
# Date: 1-30-97
|
||||
|
||||
use strict;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib ($Bin, "$Bin/../../lib/perl");
|
||||
use libcomModuleDirs;
|
||||
no lib $Bin;
|
||||
|
||||
use Getopt::Std;
|
||||
use File::Basename;
|
||||
use EPICS::Path;
|
||||
use EPICS::Release;
|
||||
use Text::Wrap;
|
||||
|
||||
my $tool = basename($0);
|
||||
|
||||
our ($opt_h, $opt_q, $opt_t, $opt_s, $opt_c);
|
||||
our $opt_o = 'envData.c';
|
||||
|
||||
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
$Text::Wrap::columns = 75;
|
||||
|
||||
HELP_MESSAGE() unless getopts('ho:qt:s:c:') && @ARGV == 1;
|
||||
HELP_MESSAGE() if $opt_h;
|
||||
|
||||
my $config = AbsPath(shift);
|
||||
my $env_defs = AbsPath('../env/envDefs.h');
|
||||
|
||||
# Parse the ENV_PARAM declarations in envDefs.h
|
||||
# to get the param names we are interested in
|
||||
#
|
||||
open SRC, '<', $env_defs
|
||||
or die "$tool: Cannot open $env_defs: $!\n";
|
||||
|
||||
my @vars;
|
||||
while (<SRC>) {
|
||||
if (m/epicsShareExtern\s+const\s+ENV_PARAM\s+([A-Za-z_]\w*)\s*;/) {
|
||||
push @vars, $1;
|
||||
}
|
||||
}
|
||||
close SRC;
|
||||
|
||||
# A list of configure/CONFIG_* files to read
|
||||
#
|
||||
my @configs = ("$config/CONFIG_ENV", "$config/CONFIG_SITE_ENV");
|
||||
|
||||
if ($opt_t) {
|
||||
my $config_arch_env = "$config/os/CONFIG_SITE_ENV.$opt_t";
|
||||
push @configs, $config_arch_env
|
||||
if -f $config_arch_env;
|
||||
}
|
||||
|
||||
my @sources = ($env_defs, @configs);
|
||||
|
||||
# Get values from the config files
|
||||
#
|
||||
my (%values, @dummy);
|
||||
readRelease($_, \%values, \@dummy) foreach @configs;
|
||||
expandRelease(\%values);
|
||||
|
||||
# Get values from the command-line
|
||||
#
|
||||
$values{EPICS_BUILD_COMPILER_CLASS} = $opt_c if $opt_c;
|
||||
$values{EPICS_BUILD_OS_CLASS} = $opt_s if $opt_s;
|
||||
$values{EPICS_BUILD_TARGET_ARCH} = $opt_t if $opt_t;
|
||||
|
||||
# Warn about vars with no configured value
|
||||
#
|
||||
my @undefs = grep {!exists $values{$_}} @vars;
|
||||
warn "$tool: No value given for $_\n" foreach @undefs;
|
||||
|
||||
print "Generating $opt_o\n" unless $opt_q;
|
||||
|
||||
# Start creating the output
|
||||
#
|
||||
open OUT, '>', $opt_o
|
||||
or die "$tool: Cannot create $opt_o: $!\n";
|
||||
|
||||
my $sources = join "\n", map {" * $_"} @sources;
|
||||
|
||||
print OUT << "END";
|
||||
/* Generated file $opt_o
|
||||
*
|
||||
* Created from
|
||||
$sources
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "envDefs.h"
|
||||
|
||||
END
|
||||
|
||||
# Define a default value for each named parameter
|
||||
#
|
||||
foreach my $var (@vars) {
|
||||
my $default = $values{$var};
|
||||
if (defined $default) {
|
||||
$default =~ s/^"//;
|
||||
$default =~ s/"$//;
|
||||
}
|
||||
else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
print OUT "epicsShareDef const ENV_PARAM $var =\n",
|
||||
" {\"$var\", \"$default\"};\n";
|
||||
}
|
||||
|
||||
# Also provide a list of all defined parameters
|
||||
#
|
||||
print OUT "\n",
|
||||
"epicsShareDef const ENV_PARAM* env_param_list[] = {\n",
|
||||
wrap(' ', ' ', join(', ', map("&$_", @vars), 'NULL')),
|
||||
"\n};\n";
|
||||
close OUT;
|
||||
|
||||
sub HELP_MESSAGE {
|
||||
print STDERR "Usage: $tool [options] configure\n",
|
||||
" -h Help: Print this message\n",
|
||||
" -q Quiet: Only print errors\n",
|
||||
" -o file Output filename, default is $opt_o\n",
|
||||
" -t arch Target architecture \$(T_A) name\n",
|
||||
" -s os Operating system \$(OS_CLASS)\n",
|
||||
" -c comp Compiler class \$(CMPLR_CLASS)\n",
|
||||
"\n";
|
||||
|
||||
exit 1;
|
||||
}
|
||||
109
modules/libcom/src/env/envDefs.h
vendored
Normal file
109
modules/libcom/src/env/envDefs.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Roger A. Cole
|
||||
* Date: 07-20-91
|
||||
*
|
||||
*/
|
||||
/****************************************************************************
|
||||
* TITLE envDefs.h - definitions for environment get/set routines
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This file defines the environment parameters for EPICS. These
|
||||
* ENV_PARAM's are created in envData.c by bldEnvData for
|
||||
* use by EPICS programs running under UNIX and VxWorks.
|
||||
*
|
||||
* User programs can define their own environment parameters for their
|
||||
* own use--the only caveat is that such parameters aren't automatically
|
||||
* setup by EPICS.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef envDefsH
|
||||
#define envDefsH
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
typedef struct envParam {
|
||||
char *name; /* text name of the parameter */
|
||||
char *pdflt;
|
||||
} ENV_PARAM;
|
||||
|
||||
/*
|
||||
* bldEnvData.pl looks for "epicsShareExtern const ENV_PARAM <name>;"
|
||||
*/
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_CONN_TMO;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_AUTO_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_REPEATER_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_SERVER_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_MAX_ARRAY_BYTES;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_AUTO_ARRAY_BYTES;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_MAX_SEARCH_PERIOD;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_NAME_SERVERS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_MCAST_TTL;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_INTF_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_IGNORE_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_AUTO_BEACON_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_ADDR_LIST;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_SERVER_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CA_BEACON_PERIOD; /* deprecated */
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PERIOD;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TIMEZONE;
|
||||
epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_IGNORE_SERVERS;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_LIMIT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_NAME;
|
||||
epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_COMMAND;
|
||||
epicsShareExtern const ENV_PARAM EPICS_CMD_PROTO_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_AR_PORT;
|
||||
epicsShareExtern const ENV_PARAM IOCSH_PS1;
|
||||
epicsShareExtern const ENV_PARAM IOCSH_HISTSIZE;
|
||||
epicsShareExtern const ENV_PARAM IOCSH_HISTEDIT_DISABLE;
|
||||
|
||||
epicsShareExtern const ENV_PARAM *env_param_list[];
|
||||
|
||||
struct in_addr;
|
||||
|
||||
epicsShareFunc char * epicsShareAPI
|
||||
envGetConfigParam(const ENV_PARAM *pParam, int bufDim, char *pBuf);
|
||||
epicsShareFunc const char * epicsShareAPI
|
||||
envGetConfigParamPtr(const ENV_PARAM *pParam);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envPrtConfigParam(const ENV_PARAM *pParam);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envGetInetAddrConfigParam(const ENV_PARAM *pParam, struct in_addr *pAddr);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envGetDoubleConfigParam(const ENV_PARAM *pParam, double *pDouble);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong);
|
||||
epicsShareFunc unsigned short epicsShareAPI envGetInetPortConfigParam
|
||||
(const ENV_PARAM *pEnv, unsigned short defaultPort);
|
||||
epicsShareFunc long epicsShareAPI
|
||||
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool);
|
||||
epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void);
|
||||
epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value);
|
||||
epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*envDefsH*/
|
||||
|
||||
426
modules/libcom/src/env/envSubr.c
vendored
Normal file
426
modules/libcom/src/env/envSubr.c
vendored
Normal file
@@ -0,0 +1,426 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author: Roger A. Cole
|
||||
* Date: 07-20-91
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE envSubr.c - routines to get and set EPICS environment parameters
|
||||
*
|
||||
* DESCRIPTION
|
||||
* These routines are oriented for use with EPICS environment
|
||||
* parameters under UNIX and VxWorks. They may be used for other
|
||||
* purposes, as well.
|
||||
*
|
||||
* Many EPICS environment parameters are predefined in envDefs.h.
|
||||
*
|
||||
* QUICK REFERENCE
|
||||
* #include "envDefs.h"
|
||||
* ENV_PARAM param;
|
||||
* char *envGetConfigParamPtr( pParam )
|
||||
* char *envGetConfigParam( pParam, bufDim, pBuf )
|
||||
* long envGetLongConfigParam( pParam, pLong )
|
||||
* long envGetDoubleConfigParam( pParam, pDouble )
|
||||
* long envGetInetAddrConfigParam( pParam, pAddr )
|
||||
* long envPrtConfigParam( pParam )
|
||||
*
|
||||
* SEE ALSO
|
||||
* $epics/share/bin/envSetupParams, envDefs.h
|
||||
*
|
||||
*-***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdlib.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "errMdef.h"
|
||||
#include "errlog.h"
|
||||
#include "envDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envGetConfigParamPtr - returns a pointer to the configuration
|
||||
* parameter value string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Returns a pointer to a configuration parameter value.
|
||||
* If the configuration parameter isn't found in the environment,
|
||||
* then a pointer to the default value for the parameter is copied.
|
||||
* If no parameter is found and there is no default, then
|
||||
* NULL is returned.
|
||||
*
|
||||
* RETURNS
|
||||
* pointer to the environment variable value string, or
|
||||
* NULL if no parameter value and no default value was found
|
||||
*
|
||||
* EXAMPLES
|
||||
* 1. Get the value for the EPICS-defined environment parameter
|
||||
* EPICS_TS_NTP_INET.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* const char *pStr;
|
||||
*
|
||||
* pStr = envGetConfigParamPtr(&EPICS_TS_NTP_INET);
|
||||
* if (pStr) {
|
||||
* printf("NTP time server is: %s\n", pStr);
|
||||
* }
|
||||
*
|
||||
*-*/
|
||||
const char * epicsShareAPI envGetConfigParamPtr(
|
||||
const ENV_PARAM *pParam /* I pointer to config param structure */
|
||||
)
|
||||
{
|
||||
const char *pEnv; /* pointer to environment string */
|
||||
|
||||
pEnv = getenv(pParam->name);
|
||||
|
||||
if (pEnv == NULL) {
|
||||
pEnv = pParam->pdflt;
|
||||
}
|
||||
|
||||
if (pEnv) {
|
||||
if (pEnv[0u] == '\0') {
|
||||
pEnv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pEnv;
|
||||
}
|
||||
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envGetConfigParam - get value of a configuration parameter
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Gets the value of a configuration parameter and copies it
|
||||
* into the caller's buffer. If the configuration parameter
|
||||
* isn't found in the environment, then the default value for
|
||||
* the parameter is copied. If no parameter is found and there
|
||||
* is no default, then '\0' is copied and NULL is returned.
|
||||
*
|
||||
* RETURNS
|
||||
* pointer to callers buffer, or
|
||||
* NULL if no parameter value or default value was found
|
||||
*
|
||||
* EXAMPLES
|
||||
* 1. Get the value for the EPICS-defined environment parameter
|
||||
* EPICS_TS_NTP_INET.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* char temp[80];
|
||||
*
|
||||
* printf("NTP time server is: %s\n",
|
||||
* envGetConfigParam(&EPICS_TS_NTP_INET, sizeof(temp), temp));
|
||||
*
|
||||
* 2. Get the value for the DISPLAY environment parameter under UNIX.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* char temp[80];
|
||||
* ENV_PARAM display={"DISPLAY",""}
|
||||
*
|
||||
* if (envGetConfigParam(&display, sizeof(temp), temp) == NULL)
|
||||
* printf("DISPLAY isn't defined\n");
|
||||
* else
|
||||
* printf("DISPLAY is %s\n", temp);
|
||||
*
|
||||
*-*/
|
||||
char * epicsShareAPI envGetConfigParam(
|
||||
const ENV_PARAM *pParam,/* I pointer to config param structure */
|
||||
int bufDim, /* I dimension of parameter buffer */
|
||||
char *pBuf /* I pointer to parameter buffer */
|
||||
)
|
||||
{
|
||||
const char *pEnv; /* pointer to environment string */
|
||||
|
||||
pEnv = envGetConfigParamPtr(pParam);
|
||||
if (!pEnv) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(pBuf, pEnv, bufDim-1);
|
||||
pBuf[bufDim-1] = '\0';
|
||||
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envGetDoubleConfigParam - get value of a double configuration parameter
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Gets the value of a configuration parameter and copies it into the
|
||||
* caller's real (double) buffer. If the configuration parameter isn't
|
||||
* found in the environment, then the default value for the parameter
|
||||
* is copied.
|
||||
*
|
||||
* If no parameter is found and there is no default, then -1 is
|
||||
* returned and the caller's buffer is unmodified.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if an error is encountered
|
||||
*
|
||||
* EXAMPLE
|
||||
* 1. Get the value for the real environment parameter EPICS_THRESHOLD.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* double threshold;
|
||||
* long status;
|
||||
*
|
||||
* status = envGetDoubleConfigParam(&EPICS_THRESHOLD, &threshold);
|
||||
* if (status == 0) {
|
||||
* printf("the threshold is: %lf\n", threshold);
|
||||
* }
|
||||
* else {
|
||||
* printf("%s could not be found or was not a real number\n",
|
||||
* EPICS_THRESHOLD.name);
|
||||
* }
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI envGetDoubleConfigParam(
|
||||
const ENV_PARAM *pParam,/* I pointer to config param structure */
|
||||
double *pDouble /* O pointer to place to store value */
|
||||
)
|
||||
{
|
||||
char text[128];
|
||||
char *ptext;
|
||||
int count;
|
||||
|
||||
ptext = envGetConfigParam(pParam, sizeof text, text);
|
||||
if (ptext != NULL) {
|
||||
count = epicsScanDouble(text, pDouble);
|
||||
if (count == 1) {
|
||||
return 0;
|
||||
}
|
||||
(void)fprintf(stderr,"Unable to find a real number in %s=%s\n",
|
||||
pParam->name, text);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envGetInetAddrConfigParam - get value of an inet addr config parameter
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Gets the value of a configuration parameter and copies it into
|
||||
* the caller's (struct in_addr) buffer. If the configuration parameter
|
||||
* isn't found in the environment, then the default value for
|
||||
* the parameter is copied.
|
||||
*
|
||||
* If no parameter is found and there is no default, then -1 is
|
||||
* returned and the callers buffer is unmodified.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if an error is encountered
|
||||
*
|
||||
* EXAMPLE
|
||||
* 1. Get the value for the inet address environment parameter EPICS_INET.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* struct in_addr addr;
|
||||
* long status;
|
||||
*
|
||||
* status = envGetInetAddrConfigParam(&EPICS_INET, &addr);
|
||||
* if (status == 0) {
|
||||
* printf("the s_addr is: %x\n", addr.s_addr);
|
||||
* }
|
||||
* else {
|
||||
* printf("%s could not be found or was not an inet address\n",
|
||||
* EPICS_INET.name);
|
||||
* }
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI envGetInetAddrConfigParam(
|
||||
const ENV_PARAM *pParam,/* I pointer to config param structure */
|
||||
struct in_addr *pAddr /* O pointer to struct to receive inet addr */
|
||||
)
|
||||
{
|
||||
char text[128];
|
||||
char *ptext;
|
||||
long status;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
ptext = envGetConfigParam(pParam, sizeof text, text);
|
||||
if (ptext) {
|
||||
status = aToIPAddr (text, 0u, &sin);
|
||||
if (status == 0) {
|
||||
*pAddr = sin.sin_addr;
|
||||
return 0;
|
||||
}
|
||||
(void)fprintf(stderr,"Unable to find an IP address or valid host name in %s=%s\n",
|
||||
pParam->name, text);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envGetLongConfigParam - get value of an integer config parameter
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Gets the value of a configuration parameter and copies it
|
||||
* into the caller's integer (long) buffer. If the configuration
|
||||
* parameter isn't found in the environment, then the default value for
|
||||
* the parameter is copied.
|
||||
*
|
||||
* If no parameter is found and there is no default, then -1 is
|
||||
* returned and the callers buffer is unmodified.
|
||||
*
|
||||
* RETURNS
|
||||
* 0, or
|
||||
* -1 if an error is encountered
|
||||
*
|
||||
* EXAMPLE
|
||||
* 1. Get the value as a long for the integer environment parameter
|
||||
* EPICS_NUMBER_OF_ITEMS.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
* long count;
|
||||
* long status;
|
||||
*
|
||||
* status = envGetLongConfigParam(&EPICS_NUMBER_OF_ITEMS, &count);
|
||||
* if (status == 0) {
|
||||
* printf("and the count is: %d\n", count);
|
||||
* }
|
||||
* else {
|
||||
* printf("%s could not be found or was not an integer\n",
|
||||
* EPICS_NUMBER_OF_ITEMS.name);
|
||||
* }
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI envGetLongConfigParam(
|
||||
const ENV_PARAM *pParam,/* I pointer to config param structure */
|
||||
long *pLong /* O pointer to place to store value */
|
||||
)
|
||||
{
|
||||
char text[128];
|
||||
char *ptext;
|
||||
int count;
|
||||
|
||||
ptext = envGetConfigParam(pParam, sizeof text, text);
|
||||
if (ptext) {
|
||||
count = sscanf(text, "%ld", pLong);
|
||||
if (count == 1)
|
||||
return 0;
|
||||
(void)fprintf(stderr,"Unable to find an integer in %s=%s\n",
|
||||
pParam->name, text);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
long epicsShareAPI
|
||||
envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool)
|
||||
{
|
||||
char text[20];
|
||||
|
||||
if(!envGetConfigParam(pParam, sizeof(text), text))
|
||||
return -1;
|
||||
*pBool = epicsStrCaseCmp(text, "yes")==0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME envPrtConfigParam - print value of a configuration parameter
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Prints the value of a configuration parameter.
|
||||
*
|
||||
* RETURNS
|
||||
* 0
|
||||
*
|
||||
* EXAMPLE
|
||||
* 1. Print the value for the EPICS-defined environment parameter
|
||||
* EPICS_TS_NTP_INET.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
*
|
||||
* envPrtConfigParam(&EPICS_TS_NTP_INET);
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI envPrtConfigParam(
|
||||
const ENV_PARAM *pParam) /* pointer to config param structure */
|
||||
{
|
||||
const char *pVal;
|
||||
|
||||
pVal = envGetConfigParamPtr(pParam);
|
||||
if (pVal == NULL)
|
||||
fprintf(stdout, "%s is undefined\n", pParam->name);
|
||||
else
|
||||
fprintf(stdout,"%s: %s\n", pParam->name, pVal);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
* NAME epicsPrtEnvParams - print value of all configuration parameters
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Prints all configuration parameters and their current value.
|
||||
*
|
||||
* RETURNS
|
||||
* 0
|
||||
*
|
||||
* EXAMPLE
|
||||
* 1. Print the value for all EPICS-defined environment parameters.
|
||||
*
|
||||
* #include "envDefs.h"
|
||||
*
|
||||
* epicsPrtEnvParams();
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI
|
||||
epicsPrtEnvParams(void)
|
||||
{
|
||||
const ENV_PARAM **ppParam = env_param_list;
|
||||
|
||||
while (*ppParam != NULL)
|
||||
envPrtConfigParam(*(ppParam++));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* envGetInetPortConfigParam ()
|
||||
*/
|
||||
epicsShareFunc unsigned short epicsShareAPI envGetInetPortConfigParam
|
||||
(const ENV_PARAM *pEnv, unsigned short defaultPort)
|
||||
{
|
||||
long longStatus;
|
||||
long epicsParam;
|
||||
|
||||
longStatus = envGetLongConfigParam (pEnv, &epicsParam);
|
||||
if (longStatus!=0) {
|
||||
epicsParam = (long) defaultPort;
|
||||
errlogPrintf ("EPICS Environment \"%s\" integer fetch failed\n", pEnv->name);
|
||||
errlogPrintf ("setting \"%s\" = %ld\n", pEnv->name, epicsParam);
|
||||
}
|
||||
|
||||
if (epicsParam<=IPPORT_USERRESERVED || epicsParam>USHRT_MAX) {
|
||||
errlogPrintf ("EPICS Environment \"%s\" out of range\n", pEnv->name);
|
||||
/*
|
||||
* Quit if the port is wrong due coding error
|
||||
*/
|
||||
assert (epicsParam != (long) defaultPort);
|
||||
epicsParam = (long) defaultPort;
|
||||
errlogPrintf ("Setting \"%s\" = %ld\n", pEnv->name, epicsParam);
|
||||
}
|
||||
|
||||
/*
|
||||
* ok to clip to unsigned short here because we checked the range
|
||||
*/
|
||||
return (unsigned short) epicsParam;
|
||||
}
|
||||
|
||||
30
modules/libcom/src/error/Makefile
Normal file
30
modules/libcom/src/error/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/error
|
||||
|
||||
INC += epicsPrint.h
|
||||
INC += errMdef.h
|
||||
INC += errSymTbl.h
|
||||
INC += errlog.h
|
||||
|
||||
Com_SRCS += errlog.c
|
||||
Com_SRCS += errSymLib.c
|
||||
Com_SRCS += errSymTbl.c
|
||||
|
||||
# For bldErrSymTbl
|
||||
#
|
||||
ERR_S_FILES += $(LIBCOM)/osi/devLib.h
|
||||
ERR_S_FILES += $(LIBCOM)/osi/epicsTime.h
|
||||
ERR_S_FILES += $(LIBCOM)/as/asLib.h
|
||||
ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h
|
||||
ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h
|
||||
ERR_S_FILES += $(LIBCOM)/error/errMdef.h
|
||||
|
||||
CLEANS += errSymTbl.c
|
||||
11
modules/libcom/src/error/RULES
Normal file
11
modules/libcom/src/error/RULES
Normal file
@@ -0,0 +1,11 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
errSymTbl.c: $(ERR_S_FILES) $(LIBCOM)/error/makeStatTbl.pl
|
||||
$(PERL) $(LIBCOM)/error/makeStatTbl.pl $(ERR_S_FILES)
|
||||
18
modules/libcom/src/error/epicsPrint.h
Normal file
18
modules/libcom/src/error/epicsPrint.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*epicsPrint.h */
|
||||
|
||||
/*This is now obsolete. Replaced by errlog.h */
|
||||
#ifndef INCepicsPrintH
|
||||
#define INCepicsPrintH
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#endif /*INCepicsPrintH*/
|
||||
47
modules/libcom/src/error/errMdef.h
Normal file
47
modules/libcom/src/error/errMdef.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* Error Handling definitions */
|
||||
/*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 6-1-90
|
||||
*/
|
||||
|
||||
#ifndef INC_errMdef_H
|
||||
#define INC_errMdef_H
|
||||
|
||||
#define RTN_SUCCESS(STATUS) ((STATUS)==0)
|
||||
|
||||
/* Module numbers start above 500 for compatibility with vxWorks errnoLib */
|
||||
|
||||
/* FIXME: M_xxx values could be declared as integer variables and set
|
||||
* at runtime from registration routines; the S_xxx definitions would
|
||||
* still work with that change, with careful initialization.
|
||||
*/
|
||||
|
||||
/* libCom */
|
||||
#define M_asLib (501 << 16) /* Access Security */
|
||||
#define M_bucket (502 << 16) /* Bucket Hash */
|
||||
#define M_devLib (503 << 16) /* Hardware RegisterAccess */
|
||||
#define M_stdlib (504 << 16) /* EPICS Standard library */
|
||||
#define M_pool (505 << 16) /* Thread pool */
|
||||
#define M_time (506 << 16) /* epicsTime */
|
||||
|
||||
/* ioc */
|
||||
#define M_dbAccess (511 << 16) /* Database Access Routines */
|
||||
#define M_dbLib (512 << 16) /* Static Database Access */
|
||||
#define M_drvSup (513 << 16) /* Driver Support */
|
||||
#define M_devSup (514 << 16) /* Device Support */
|
||||
#define M_recSup (515 << 16) /* Record Support */
|
||||
|
||||
/* cas */
|
||||
#define M_cas (521 << 16) /* CA server */
|
||||
#define M_gddFuncTbl (522 << 16) /* gdd jump table */
|
||||
#define M_casApp (523 << 16) /* CA server application */
|
||||
|
||||
#endif /*INC_errMdef_H*/
|
||||
282
modules/libcom/src/error/errSymLib.c
Normal file
282
modules/libcom/src/error/errSymLib.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* errSymLib.c
|
||||
* Author: Marty Kraimer
|
||||
* Date: 6-1-90
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "errMdef.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "ellLib.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#define NHASH 256
|
||||
|
||||
static epicsUInt16 errhash(long errNum);
|
||||
|
||||
typedef struct errnumnode {
|
||||
ELLNODE node;
|
||||
long errNum;
|
||||
struct errnumnode *hashnode;
|
||||
const char *message;
|
||||
long pad;
|
||||
} ERRNUMNODE;
|
||||
|
||||
static ELLLIST errnumlist = ELLLIST_INIT;
|
||||
static ERRNUMNODE **hashtable;
|
||||
static int initialized = 0;
|
||||
extern ERRSYMTAB_ID errSymTbl;
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMBLD
|
||||
*
|
||||
* Create the normal ell LIST of sorted error messages nodes
|
||||
* Followed by linked hash lists - that link together those
|
||||
* ell nodes that have a common hash number.
|
||||
*
|
||||
***************************************************************/
|
||||
int errSymBld(void)
|
||||
{
|
||||
ERRSYMBOL *errArray = errSymTbl->symbols;
|
||||
ERRNUMNODE *perrNumNode = NULL;
|
||||
ERRNUMNODE *pNextNode = NULL;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
int i;
|
||||
int modnum;
|
||||
|
||||
if (initialized)
|
||||
return(0);
|
||||
|
||||
hashtable = (ERRNUMNODE**)callocMustSucceed
|
||||
(NHASH, sizeof(ERRNUMNODE*),"errSymBld");
|
||||
for (i = 0; i < errSymTbl->nsymbols; i++, errArray++) {
|
||||
modnum = errArray->errNum >> 16;
|
||||
if (modnum < 501) {
|
||||
fprintf(stderr, "errSymBld: ERROR - Module number in errSymTbl < 501 was Module=%lx Name=%s\n",
|
||||
errArray->errNum, errArray->name);
|
||||
continue;
|
||||
}
|
||||
if ((errSymbolAdd(errArray->errNum, errArray->name)) < 0) {
|
||||
fprintf(stderr, "errSymBld: ERROR - errSymbolAdd() failed \n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist);
|
||||
while (perrNumNode) {
|
||||
/* hash each perrNumNode->errNum */
|
||||
epicsUInt16 hashInd = errhash(perrNumNode->errNum);
|
||||
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
pNextNode = (ERRNUMNODE*) *phashnode;
|
||||
/* search for last node (NULL) of hashnode linked list */
|
||||
while (pNextNode) {
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
*phashnode = perrNumNode;
|
||||
perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
|
||||
}
|
||||
initialized = 1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* HASH
|
||||
* returns the hash index of errNum
|
||||
****************************************************************/
|
||||
static epicsUInt16 errhash(long errNum)
|
||||
{
|
||||
epicsUInt16 modnum;
|
||||
epicsUInt16 errnum;
|
||||
|
||||
modnum = (unsigned short) (errNum >> 16);
|
||||
errnum = (unsigned short) (errNum & 0xffff);
|
||||
return (((modnum - 500) * 20) + errnum) % NHASH;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMBOLADD
|
||||
* adds symbols to the master errnumlist as compiled from errSymTbl.c
|
||||
***************************************************************/
|
||||
int errSymbolAdd(long errNum, const char *name)
|
||||
{
|
||||
ERRNUMNODE *pNew = (ERRNUMNODE*) callocMustSucceed(1,
|
||||
sizeof(ERRNUMNODE), "errSymbolAdd");
|
||||
|
||||
pNew->errNum = errNum;
|
||||
pNew->message = name;
|
||||
ellAdd(&errnumlist, (ELLNODE*)pNew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* errRawCopy
|
||||
***************************************************************/
|
||||
static void errRawCopy(long statusToDecode, char *pBuf, size_t bufLength)
|
||||
{
|
||||
epicsUInt16 modnum = (statusToDecode >>= 16) & 0xffff;
|
||||
epicsUInt16 errnum = statusToDecode & 0xffff;
|
||||
|
||||
assert(bufLength > 20);
|
||||
|
||||
if (modnum == 0) {
|
||||
epicsSnprintf(pBuf, bufLength, "Error #%u", errnum);
|
||||
}
|
||||
else {
|
||||
epicsSnprintf(pBuf, bufLength, "Error (%u,%u)", modnum, errnum);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
const char* errSymLookupInternal(long status)
|
||||
{
|
||||
unsigned modNum;
|
||||
ERRNUMNODE *pNextNode;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
|
||||
if (!initialized)
|
||||
errSymBld();
|
||||
|
||||
modNum = (unsigned) status;
|
||||
modNum >>= 16;
|
||||
modNum &= 0xffff;
|
||||
if (modNum <= 500) {
|
||||
const char * pStr = strerror ((int) status);
|
||||
if (pStr) {
|
||||
return pStr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned hashInd = errhash(status);
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
pNextNode = *phashnode;
|
||||
while (pNextNode) {
|
||||
if (pNextNode->errNum==status){
|
||||
return pNextNode->message;
|
||||
}
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* errSymMsg(long status)
|
||||
{
|
||||
const char* msg = errSymLookupInternal(status);
|
||||
return msg ? msg : "<Unknown code>";
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* errSymLookup
|
||||
***************************************************************/
|
||||
void errSymLookup(long status, char * pBuf, size_t bufLength)
|
||||
{
|
||||
const char* msg = errSymLookupInternal(status);
|
||||
if(msg) {
|
||||
strncpy(pBuf, msg, bufLength);
|
||||
pBuf[bufLength-1] = '\0';
|
||||
return;
|
||||
}
|
||||
errRawCopy(status, pBuf, bufLength);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* errSymDump
|
||||
***************************************************************/
|
||||
void errSymDump(void)
|
||||
{
|
||||
int i;
|
||||
int msgcount = 0;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
|
||||
msgcount = 0;
|
||||
printf("errSymDump: number of hash slots = %d\n", NHASH);
|
||||
for (i = 0; i < NHASH; i++) {
|
||||
ERRNUMNODE **phashnode = &hashtable[i];
|
||||
ERRNUMNODE *pNextNode = *phashnode;
|
||||
int count = 0;
|
||||
|
||||
while (pNextNode) {
|
||||
int modnum = pNextNode->errNum >> 16;
|
||||
int errnum = pNextNode->errNum & 0xffff;
|
||||
|
||||
if (!count++) {
|
||||
printf("HASHNODE = %d\n", i);
|
||||
}
|
||||
printf("\tmod %d num %d \"%s\"\n",
|
||||
modnum , errnum , pNextNode->message);
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
msgcount += count;
|
||||
}
|
||||
printf("\nerrSymDump: total number of error messages = %d\n", msgcount);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* errSymTestPrint
|
||||
***************************************************************/
|
||||
void errSymTestPrint(long errNum)
|
||||
{
|
||||
char message[256];
|
||||
epicsUInt16 modnum;
|
||||
epicsUInt16 errnum;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
|
||||
message[0] = '\0';
|
||||
modnum = (epicsUInt16) (errNum >> 16);
|
||||
errnum = (epicsUInt16) (errNum & 0xffff);
|
||||
if (modnum < 501) {
|
||||
fprintf(stderr, "Usage: errSymTestPrint(long errNum) \n");
|
||||
fprintf(stderr, "errSymTestPrint: module number < 501 \n");
|
||||
return;
|
||||
}
|
||||
errSymLookup(errNum, message, sizeof(message));
|
||||
if ( message[0] == '\0' ) return;
|
||||
printf("module %hu number %hu message=\"%s\"\n",
|
||||
modnum, errnum, message);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMTEST
|
||||
****************************************************************/
|
||||
void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
|
||||
epicsUInt16 endErrNum)
|
||||
{
|
||||
long errNum;
|
||||
epicsUInt16 errnum;
|
||||
|
||||
if (!initialized) errSymBld();
|
||||
if (modnum < 501)
|
||||
return;
|
||||
|
||||
/* print range of error messages */
|
||||
for (errnum = begErrNum; errnum <= endErrNum; errnum++) {
|
||||
errNum = modnum << 16;
|
||||
errNum |= (errnum & 0xffff);
|
||||
errSymTestPrint(errNum);
|
||||
}
|
||||
}
|
||||
50
modules/libcom/src/error/errSymTbl.h
Normal file
50
modules/libcom/src/error/errSymTbl.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INC_errSymTbl_H
|
||||
#define INC_errSymTbl_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "epicsTypes.h"
|
||||
|
||||
/* ERRSYMBOL - entry in symbol table */
|
||||
typedef struct {
|
||||
long errNum; /* errMessage symbol number */
|
||||
const char *name; /* pointer to symbol name */
|
||||
} ERRSYMBOL;
|
||||
|
||||
/* ERRSYMTAB - symbol table */
|
||||
typedef struct {
|
||||
int nsymbols; /* current number of symbols in table */
|
||||
ERRSYMBOL *symbols; /* ptr to array of symbol entries */
|
||||
} ERRSYMTAB;
|
||||
|
||||
typedef ERRSYMTAB *ERRSYMTAB_ID;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
epicsShareFunc const char* errSymMsg(long status);
|
||||
epicsShareFunc void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum,
|
||||
epicsUInt16 endErrNum);
|
||||
epicsShareFunc void errSymTestPrint(long errNum);
|
||||
epicsShareFunc int errSymBld(void);
|
||||
epicsShareFunc int errSymbolAdd(long errNum, const char *name);
|
||||
epicsShareFunc void errSymDump(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INC_errSymTbl_H */
|
||||
695
modules/libcom/src/error/errlog.c
Normal file
695
modules/libcom/src/error/errlog.c
Normal file
@@ -0,0 +1,695 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
* Date: 07JAN1998
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#define ERRLOG_INIT
|
||||
#include "adjustment.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsInterrupt.h"
|
||||
#include "errMdef.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "ellLib.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsExit.h"
|
||||
|
||||
|
||||
#define BUFFER_SIZE 1280
|
||||
#define MAX_MESSAGE_SIZE 256
|
||||
|
||||
/*Declare storage for errVerbose */
|
||||
epicsShareDef int errVerbose = 0;
|
||||
|
||||
static void errlogExitHandler(void *);
|
||||
static void errlogThread(void);
|
||||
|
||||
static char *msgbufGetFree(int noConsoleMessage);
|
||||
static void msgbufSetSize(int size); /* Send 'size' chars plus trailing '\0' */
|
||||
static char *msgbufGetSend(int *noConsoleMessage);
|
||||
static void msgbufFreeSend(void);
|
||||
|
||||
typedef struct listenerNode{
|
||||
ELLNODE node;
|
||||
errlogListener listener;
|
||||
void *pPrivate;
|
||||
} listenerNode;
|
||||
|
||||
/*each message consists of a msgNode immediately followed by the message */
|
||||
typedef struct msgNode {
|
||||
ELLNODE node;
|
||||
char *message;
|
||||
int length;
|
||||
int noConsoleMessage;
|
||||
} msgNode;
|
||||
|
||||
static struct {
|
||||
epicsEventId waitForWork; /*errlogThread waits for this*/
|
||||
epicsMutexId msgQueueLock;
|
||||
epicsMutexId listenerLock;
|
||||
epicsEventId waitForFlush; /*errlogFlush waits for this*/
|
||||
epicsEventId flush; /*errlogFlush sets errlogThread does a Try*/
|
||||
epicsMutexId flushLock;
|
||||
epicsEventId waitForExit; /*errlogExitHandler waits for this*/
|
||||
int atExit; /*TRUE when errlogExitHandler is active*/
|
||||
ELLLIST listenerList;
|
||||
ELLLIST msgQueue;
|
||||
msgNode *pnextSend;
|
||||
int errlogInitFailed;
|
||||
int buffersize;
|
||||
int maxMsgSize;
|
||||
int msgNeeded;
|
||||
int sevToLog;
|
||||
int toConsole;
|
||||
FILE *console;
|
||||
int missedMessages;
|
||||
char *pbuffer;
|
||||
} pvtData;
|
||||
|
||||
|
||||
/*
|
||||
* vsnprintf with truncation message
|
||||
*/
|
||||
static int tvsnPrint(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
static const char tmsg[] = "<<TRUNCATED>>\n";
|
||||
int nchar = epicsVsnprintf(str, size, format ? format : "", ap);
|
||||
|
||||
if (nchar >= size) {
|
||||
if (size > sizeof tmsg)
|
||||
strcpy(str + size - sizeof tmsg, tmsg);
|
||||
nchar = size - 1;
|
||||
}
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int errlogPrintf(const char *pFormat, ...)
|
||||
{
|
||||
va_list pvar;
|
||||
char *pbuffer;
|
||||
int nchar;
|
||||
int isOkToBlock;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogPrintf called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
isOkToBlock = epicsThreadIsOkToBlock();
|
||||
|
||||
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
va_start(pvar, pFormat);
|
||||
nchar = vfprintf(console, pFormat, pvar);
|
||||
va_end (pvar);
|
||||
fflush(console);
|
||||
}
|
||||
|
||||
if (pvtData.atExit)
|
||||
return nchar;
|
||||
|
||||
pbuffer = msgbufGetFree(isOkToBlock);
|
||||
if (!pbuffer)
|
||||
return 0;
|
||||
|
||||
va_start(pvar, pFormat);
|
||||
nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
|
||||
va_end(pvar);
|
||||
msgbufSetSize(nchar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int errlogVprintf(const char *pFormat,va_list pvar)
|
||||
{
|
||||
int nchar;
|
||||
char *pbuffer;
|
||||
int isOkToBlock;
|
||||
FILE *console;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogVprintf called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.atExit)
|
||||
return 0;
|
||||
isOkToBlock = epicsThreadIsOkToBlock();
|
||||
|
||||
pbuffer = msgbufGetFree(isOkToBlock);
|
||||
if (!pbuffer) {
|
||||
console = pvtData.console ? pvtData.console : stderr;
|
||||
vfprintf(console, pFormat, pvar);
|
||||
fflush(console);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
|
||||
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
|
||||
console = pvtData.console ? pvtData.console : stderr;
|
||||
fprintf(console, "%s", pbuffer);
|
||||
fflush(console);
|
||||
}
|
||||
msgbufSetSize(nchar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int errlogMessage(const char *message)
|
||||
{
|
||||
errlogPrintf("%s", message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int errlogPrintfNoConsole(const char *pFormat, ...)
|
||||
{
|
||||
va_list pvar;
|
||||
int nchar;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogPrintfNoConsole called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
va_start(pvar, pFormat);
|
||||
nchar = errlogVprintfNoConsole(pFormat, pvar);
|
||||
va_end(pvar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int errlogVprintfNoConsole(const char *pFormat, va_list pvar)
|
||||
{
|
||||
int nchar;
|
||||
char *pbuffer;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogVprintfNoConsole called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.atExit)
|
||||
return 0;
|
||||
|
||||
pbuffer = msgbufGetFree(1);
|
||||
if (!pbuffer)
|
||||
return 0;
|
||||
|
||||
nchar = tvsnPrint(pbuffer, pvtData.maxMsgSize, pFormat?pFormat:"", pvar);
|
||||
msgbufSetSize(nchar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
|
||||
int errlogSevPrintf(errlogSevEnum severity, const char *pFormat, ...)
|
||||
{
|
||||
va_list pvar;
|
||||
int nchar;
|
||||
int isOkToBlock;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogSevPrintf called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.sevToLog > severity)
|
||||
return 0;
|
||||
|
||||
isOkToBlock = epicsThreadIsOkToBlock();
|
||||
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
fprintf(console, "sevr=%s ", errlogGetSevEnumString(severity));
|
||||
va_start(pvar, pFormat);
|
||||
vfprintf(console, pFormat, pvar);
|
||||
va_end(pvar);
|
||||
fflush(console);
|
||||
}
|
||||
|
||||
va_start(pvar, pFormat);
|
||||
nchar = errlogSevVprintf(severity, pFormat, pvar);
|
||||
va_end(pvar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
int errlogSevVprintf(errlogSevEnum severity, const char *pFormat, va_list pvar)
|
||||
{
|
||||
char *pnext;
|
||||
int nchar;
|
||||
int totalChar = 0;
|
||||
int isOkToBlock;
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage
|
||||
("errlogSevVprintf called from interrupt level\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.atExit)
|
||||
return 0;
|
||||
|
||||
isOkToBlock = epicsThreadIsOkToBlock();
|
||||
pnext = msgbufGetFree(isOkToBlock);
|
||||
if (!pnext)
|
||||
return 0;
|
||||
|
||||
nchar = sprintf(pnext, "sevr=%s ", errlogGetSevEnumString(severity));
|
||||
pnext += nchar; totalChar += nchar;
|
||||
nchar = tvsnPrint(pnext, pvtData.maxMsgSize - totalChar - 1, pFormat, pvar);
|
||||
pnext += nchar; totalChar += nchar;
|
||||
if (pnext[-1] != '\n') {
|
||||
strcpy(pnext,"\n");
|
||||
totalChar++;
|
||||
}
|
||||
msgbufSetSize(totalChar);
|
||||
return nchar;
|
||||
}
|
||||
|
||||
|
||||
const char * errlogGetSevEnumString(errlogSevEnum severity)
|
||||
{
|
||||
errlogInit(0);
|
||||
if (severity > 3)
|
||||
return "unknown";
|
||||
return errlogSevEnumString[severity];
|
||||
}
|
||||
|
||||
void errlogSetSevToLog(errlogSevEnum severity)
|
||||
{
|
||||
errlogInit(0);
|
||||
pvtData.sevToLog = severity;
|
||||
}
|
||||
|
||||
errlogSevEnum errlogGetSevToLog(void)
|
||||
{
|
||||
errlogInit(0);
|
||||
return pvtData.sevToLog;
|
||||
}
|
||||
|
||||
void errlogAddListener(errlogListener listener, void *pPrivate)
|
||||
{
|
||||
listenerNode *plistenerNode;
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.atExit)
|
||||
return;
|
||||
|
||||
plistenerNode = callocMustSucceed(1,sizeof(listenerNode),
|
||||
"errlogAddListener");
|
||||
epicsMutexMustLock(pvtData.listenerLock);
|
||||
plistenerNode->listener = listener;
|
||||
plistenerNode->pPrivate = pPrivate;
|
||||
ellAdd(&pvtData.listenerList,&plistenerNode->node);
|
||||
epicsMutexUnlock(pvtData.listenerLock);
|
||||
}
|
||||
|
||||
int errlogRemoveListeners(errlogListener listener, void *pPrivate)
|
||||
{
|
||||
listenerNode *plistenerNode;
|
||||
int count = 0;
|
||||
|
||||
errlogInit(0);
|
||||
if (!pvtData.atExit)
|
||||
epicsMutexMustLock(pvtData.listenerLock);
|
||||
|
||||
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
|
||||
while (plistenerNode) {
|
||||
listenerNode *pnext = (listenerNode *)ellNext(&plistenerNode->node);
|
||||
|
||||
if (plistenerNode->listener == listener &&
|
||||
plistenerNode->pPrivate == pPrivate) {
|
||||
ellDelete(&pvtData.listenerList, &plistenerNode->node);
|
||||
free(plistenerNode);
|
||||
++count;
|
||||
}
|
||||
plistenerNode = pnext;
|
||||
}
|
||||
|
||||
if (!pvtData.atExit)
|
||||
epicsMutexUnlock(pvtData.listenerLock);
|
||||
|
||||
if (count == 0) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
fprintf(console,
|
||||
"errlogRemoveListeners: No listeners found\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int eltc(int yesno)
|
||||
{
|
||||
errlogInit(0);
|
||||
errlogFlush();
|
||||
pvtData.toConsole = yesno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int errlogSetConsole(FILE *stream)
|
||||
{
|
||||
errlogInit(0);
|
||||
pvtData.console = stream;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void errPrintf(long status, const char *pFileName, int lineno,
|
||||
const char *pformat, ...)
|
||||
{
|
||||
va_list pvar;
|
||||
char *pnext;
|
||||
int nchar;
|
||||
int totalChar=0;
|
||||
int isOkToBlock;
|
||||
char name[256];
|
||||
|
||||
if (epicsInterruptIsInterruptContext()) {
|
||||
epicsInterruptContextMessage("errPrintf called from interrupt level\n");
|
||||
return;
|
||||
}
|
||||
|
||||
errlogInit(0);
|
||||
isOkToBlock = epicsThreadIsOkToBlock();
|
||||
if (status == 0)
|
||||
status = errno;
|
||||
|
||||
if (status > 0) {
|
||||
errSymLookup(status, name, sizeof(name));
|
||||
}
|
||||
|
||||
if (pvtData.atExit || (isOkToBlock && pvtData.toConsole)) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
if (pFileName)
|
||||
fprintf(console, "filename=\"%s\" line number=%d\n",
|
||||
pFileName, lineno);
|
||||
if (status > 0)
|
||||
fprintf(console, "%s ", name);
|
||||
|
||||
va_start(pvar, pformat);
|
||||
vfprintf(console, pformat, pvar);
|
||||
va_end(pvar);
|
||||
fputc('\n', console);
|
||||
fflush(console);
|
||||
}
|
||||
|
||||
if (pvtData.atExit)
|
||||
return;
|
||||
|
||||
pnext = msgbufGetFree(isOkToBlock);
|
||||
if (!pnext)
|
||||
return;
|
||||
|
||||
if (pFileName) {
|
||||
nchar = sprintf(pnext,"filename=\"%s\" line number=%d\n",
|
||||
pFileName, lineno);
|
||||
pnext += nchar; totalChar += nchar;
|
||||
}
|
||||
|
||||
if (status > 0) {
|
||||
nchar = sprintf(pnext,"%s ",name);
|
||||
pnext += nchar; totalChar += nchar;
|
||||
}
|
||||
va_start(pvar, pformat);
|
||||
nchar = tvsnPrint(pnext, pvtData.maxMsgSize - totalChar - 1, pformat, pvar);
|
||||
va_end(pvar);
|
||||
if (nchar>0) {
|
||||
pnext += nchar;
|
||||
totalChar += nchar;
|
||||
}
|
||||
strcpy(pnext, "\n");
|
||||
totalChar++ ; /*include the \n */
|
||||
msgbufSetSize(totalChar);
|
||||
}
|
||||
|
||||
|
||||
static void errlogExitHandler(void *pvt)
|
||||
{
|
||||
pvtData.atExit = 1;
|
||||
epicsEventSignal(pvtData.waitForWork);
|
||||
epicsEventMustWait(pvtData.waitForExit);
|
||||
}
|
||||
|
||||
struct initArgs {
|
||||
int bufsize;
|
||||
int maxMsgSize;
|
||||
};
|
||||
|
||||
static void errlogInitPvt(void *arg)
|
||||
{
|
||||
struct initArgs *pconfig = (struct initArgs *) arg;
|
||||
epicsThreadId tid;
|
||||
|
||||
pvtData.errlogInitFailed = TRUE;
|
||||
pvtData.buffersize = pconfig->bufsize;
|
||||
pvtData.maxMsgSize = pconfig->maxMsgSize;
|
||||
pvtData.msgNeeded = adjustToWorstCaseAlignment(pvtData.maxMsgSize +
|
||||
sizeof(msgNode));
|
||||
ellInit(&pvtData.listenerList);
|
||||
ellInit(&pvtData.msgQueue);
|
||||
pvtData.toConsole = TRUE;
|
||||
pvtData.console = NULL;
|
||||
pvtData.waitForWork = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvtData.listenerLock = epicsMutexMustCreate();
|
||||
pvtData.msgQueueLock = epicsMutexMustCreate();
|
||||
pvtData.waitForFlush = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvtData.flush = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvtData.flushLock = epicsMutexMustCreate();
|
||||
pvtData.waitForExit = epicsEventMustCreate(epicsEventEmpty);
|
||||
pvtData.pbuffer = callocMustSucceed(1, pvtData.buffersize,
|
||||
"errlogInitPvt");
|
||||
|
||||
errSymBld(); /* Better not to do this lazily... */
|
||||
|
||||
tid = epicsThreadCreate("errlog", epicsThreadPriorityLow,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
(EPICSTHREADFUNC)errlogThread, 0);
|
||||
if (tid) {
|
||||
pvtData.errlogInitFailed = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int errlogInit2(int bufsize, int maxMsgSize)
|
||||
{
|
||||
static epicsThreadOnceId errlogOnceFlag = EPICS_THREAD_ONCE_INIT;
|
||||
struct initArgs config;
|
||||
|
||||
if (pvtData.atExit)
|
||||
return 0;
|
||||
|
||||
if (bufsize < BUFFER_SIZE)
|
||||
bufsize = BUFFER_SIZE;
|
||||
config.bufsize = bufsize;
|
||||
|
||||
if (maxMsgSize < MAX_MESSAGE_SIZE)
|
||||
maxMsgSize = MAX_MESSAGE_SIZE;
|
||||
config.maxMsgSize = maxMsgSize;
|
||||
|
||||
epicsThreadOnce(&errlogOnceFlag, errlogInitPvt, &config);
|
||||
if (pvtData.errlogInitFailed) {
|
||||
fprintf(stderr,"errlogInit failed\n");
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int errlogInit(int bufsize)
|
||||
{
|
||||
return errlogInit2(bufsize, MAX_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
void errlogFlush(void)
|
||||
{
|
||||
int count;
|
||||
|
||||
errlogInit(0);
|
||||
if (pvtData.atExit)
|
||||
return;
|
||||
|
||||
/*If nothing in queue dont wake up errlogThread*/
|
||||
epicsMutexMustLock(pvtData.msgQueueLock);
|
||||
count = ellCount(&pvtData.msgQueue);
|
||||
epicsMutexUnlock(pvtData.msgQueueLock);
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
/*must let errlogThread empty queue*/
|
||||
epicsMutexMustLock(pvtData.flushLock);
|
||||
epicsEventSignal(pvtData.flush);
|
||||
epicsEventSignal(pvtData.waitForWork);
|
||||
epicsEventMustWait(pvtData.waitForFlush);
|
||||
epicsMutexUnlock(pvtData.flushLock);
|
||||
}
|
||||
|
||||
static void errlogThread(void)
|
||||
{
|
||||
listenerNode *plistenerNode;
|
||||
int noConsoleMessage;
|
||||
char *pmessage;
|
||||
|
||||
epicsAtExit(errlogExitHandler,0);
|
||||
while (TRUE) {
|
||||
epicsEventMustWait(pvtData.waitForWork);
|
||||
while ((pmessage = msgbufGetSend(&noConsoleMessage))) {
|
||||
epicsMutexMustLock(pvtData.listenerLock);
|
||||
if (pvtData.toConsole && !noConsoleMessage) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
fprintf(console, "%s", pmessage);
|
||||
fflush(console);
|
||||
}
|
||||
|
||||
plistenerNode = (listenerNode *)ellFirst(&pvtData.listenerList);
|
||||
while (plistenerNode) {
|
||||
(*plistenerNode->listener)(plistenerNode->pPrivate, pmessage);
|
||||
plistenerNode = (listenerNode *)ellNext(&plistenerNode->node);
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pvtData.listenerLock);
|
||||
msgbufFreeSend();
|
||||
}
|
||||
|
||||
if (pvtData.atExit)
|
||||
break;
|
||||
if (epicsEventTryWait(pvtData.flush) != epicsEventWaitOK)
|
||||
continue;
|
||||
|
||||
epicsThreadSleep(.2); /*just wait an extra .2 seconds*/
|
||||
epicsEventSignal(pvtData.waitForFlush);
|
||||
}
|
||||
epicsEventSignal(pvtData.waitForExit);
|
||||
}
|
||||
|
||||
|
||||
static msgNode * msgbufGetNode(void)
|
||||
{
|
||||
char *pbuffer = pvtData.pbuffer;
|
||||
char *pnextFree;
|
||||
msgNode *pnextSend;
|
||||
|
||||
if (ellCount(&pvtData.msgQueue) == 0 ) {
|
||||
pnextFree = pbuffer; /* Reset if empty */
|
||||
}
|
||||
else {
|
||||
msgNode *pfirst = (msgNode *)ellFirst(&pvtData.msgQueue);
|
||||
msgNode *plast = (msgNode *)ellLast(&pvtData.msgQueue);
|
||||
char *plimit = pbuffer + pvtData.buffersize;
|
||||
|
||||
pnextFree = plast->message + adjustToWorstCaseAlignment(plast->length);
|
||||
if (pfirst > plast) {
|
||||
plimit = (char *)pfirst;
|
||||
}
|
||||
else if (pnextFree + pvtData.msgNeeded > plimit) {
|
||||
pnextFree = pbuffer; /* Hit end, wrap to start */
|
||||
plimit = (char *)pfirst;
|
||||
}
|
||||
if (pnextFree + pvtData.msgNeeded > plimit) {
|
||||
return 0; /* No room */
|
||||
}
|
||||
}
|
||||
|
||||
pnextSend = (msgNode *)pnextFree;
|
||||
pnextSend->message = pnextFree + sizeof(msgNode);
|
||||
pnextSend->length = 0;
|
||||
return pnextSend;
|
||||
}
|
||||
|
||||
static char * msgbufGetFree(int noConsoleMessage)
|
||||
{
|
||||
msgNode *pnextSend;
|
||||
|
||||
if (epicsMutexLock(pvtData.msgQueueLock) != epicsMutexLockOK)
|
||||
return 0;
|
||||
|
||||
if ((ellCount(&pvtData.msgQueue) == 0) && pvtData.missedMessages) {
|
||||
int nchar;
|
||||
|
||||
pnextSend = msgbufGetNode();
|
||||
nchar = sprintf(pnextSend->message,
|
||||
"errlog: %d messages were discarded\n", pvtData.missedMessages);
|
||||
pnextSend->length = nchar + 1;
|
||||
pvtData.missedMessages = 0;
|
||||
ellAdd(&pvtData.msgQueue, &pnextSend->node);
|
||||
}
|
||||
|
||||
pvtData.pnextSend = pnextSend = msgbufGetNode();
|
||||
if (pnextSend) {
|
||||
pnextSend->noConsoleMessage = noConsoleMessage;
|
||||
pnextSend->length = 0;
|
||||
return pnextSend->message; /* NB: msgQueueLock is still locked */
|
||||
}
|
||||
|
||||
++pvtData.missedMessages;
|
||||
epicsMutexUnlock(pvtData.msgQueueLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msgbufSetSize(int size)
|
||||
{
|
||||
msgNode *pnextSend = pvtData.pnextSend;
|
||||
|
||||
pnextSend->length = size+1;
|
||||
ellAdd(&pvtData.msgQueue, &pnextSend->node);
|
||||
epicsMutexUnlock(pvtData.msgQueueLock);
|
||||
epicsEventSignal(pvtData.waitForWork);
|
||||
}
|
||||
|
||||
|
||||
static char * msgbufGetSend(int *noConsoleMessage)
|
||||
{
|
||||
msgNode *pnextSend;
|
||||
|
||||
epicsMutexMustLock(pvtData.msgQueueLock);
|
||||
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
|
||||
epicsMutexUnlock(pvtData.msgQueueLock);
|
||||
if (!pnextSend)
|
||||
return 0;
|
||||
|
||||
*noConsoleMessage = pnextSend->noConsoleMessage;
|
||||
return pnextSend->message;
|
||||
}
|
||||
|
||||
static void msgbufFreeSend(void)
|
||||
{
|
||||
msgNode *pnextSend;
|
||||
|
||||
epicsMutexMustLock(pvtData.msgQueueLock);
|
||||
pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
|
||||
if (!pnextSend) {
|
||||
FILE *console = pvtData.console ? pvtData.console : stderr;
|
||||
|
||||
fprintf(console, "errlog: msgbufFreeSend logic error\n");
|
||||
epicsThreadSuspendSelf();
|
||||
}
|
||||
ellDelete(&pvtData.msgQueue, &pnextSend->node);
|
||||
epicsMutexUnlock(pvtData.msgQueueLock);
|
||||
}
|
||||
91
modules/libcom/src/error/errlog.h
Normal file
91
modules/libcom/src/error/errlog.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INC_errlog_H
|
||||
#define INC_errlog_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*errlogListener)(void *pPrivate, const char *message);
|
||||
|
||||
typedef enum {
|
||||
errlogInfo,
|
||||
errlogMinor,
|
||||
errlogMajor,
|
||||
errlogFatal
|
||||
} errlogSevEnum;
|
||||
|
||||
epicsShareExtern int errVerbose;
|
||||
|
||||
|
||||
#ifdef ERRLOG_INIT
|
||||
epicsShareDef const char *errlogSevEnumString[] = {
|
||||
"info",
|
||||
"minor",
|
||||
"major",
|
||||
"fatal"
|
||||
};
|
||||
#else
|
||||
epicsShareExtern const char * errlogSevEnumString[];
|
||||
#endif
|
||||
|
||||
/* errMessage is a macro so it can get the file and line number */
|
||||
#define errMessage(S, PM) \
|
||||
errPrintf(S, __FILE__, __LINE__, "%s", PM)
|
||||
/* epicsPrintf and epicsVprintf are old names for errlog routines*/
|
||||
#define epicsPrintf errlogPrintf
|
||||
#define epicsVprintf errlogVprintf
|
||||
|
||||
epicsShareFunc int errlogPrintf(const char *pformat, ...)
|
||||
EPICS_PRINTF_STYLE(1,2);
|
||||
epicsShareFunc int errlogVprintf(const char *pformat, va_list pvar);
|
||||
epicsShareFunc int errlogSevPrintf(const errlogSevEnum severity,
|
||||
const char *pformat, ...) EPICS_PRINTF_STYLE(2,3);
|
||||
epicsShareFunc int errlogSevVprintf(const errlogSevEnum severity,
|
||||
const char *pformat, va_list pvar);
|
||||
epicsShareFunc int errlogMessage(const char *message);
|
||||
|
||||
epicsShareFunc const char * errlogGetSevEnumString(errlogSevEnum severity);
|
||||
epicsShareFunc void errlogSetSevToLog(errlogSevEnum severity);
|
||||
epicsShareFunc errlogSevEnum errlogGetSevToLog(void);
|
||||
|
||||
epicsShareFunc void errlogAddListener(errlogListener listener, void *pPrivate);
|
||||
epicsShareFunc int errlogRemoveListeners(errlogListener listener,
|
||||
void *pPrivate);
|
||||
|
||||
epicsShareFunc int eltc(int yesno);
|
||||
epicsShareFunc int errlogSetConsole(FILE *stream);
|
||||
|
||||
epicsShareFunc int errlogInit(int bufsize);
|
||||
epicsShareFunc int errlogInit2(int bufsize, int maxMsgSize);
|
||||
epicsShareFunc void errlogFlush(void);
|
||||
|
||||
epicsShareFunc void errPrintf(long status, const char *pFileName, int lineno,
|
||||
const char *pformat, ...) EPICS_PRINTF_STYLE(4,5);
|
||||
|
||||
epicsShareFunc int errlogPrintfNoConsole(const char *pformat, ...)
|
||||
EPICS_PRINTF_STYLE(1,2);
|
||||
epicsShareFunc int errlogVprintfNoConsole(const char *pformat,va_list pvar);
|
||||
|
||||
epicsShareFunc void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INC_errlog_H*/
|
||||
116
modules/libcom/src/error/makeStatTbl.pl
Normal file
116
modules/libcom/src/error/makeStatTbl.pl
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2014 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
#
|
||||
# makeStatTbl.pl - Create Error Symbol Table
|
||||
#
|
||||
# Original Author: Kay-Uwe Kasemir, 1-31-97
|
||||
#
|
||||
# SYNOPSIS
|
||||
# perl makeStatTbl.pl files.h...
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This tool creates a symbol table (ERRSYMTAB) structure which contains the
|
||||
# names and values of all the status codes defined in the .h files named in
|
||||
# its input arguments. The status codes must be prefixed with "S_"
|
||||
# in order to be included in this table.
|
||||
# Module numbers definitions prefixed with "M_" are also read from the input
|
||||
# files and included in the output.
|
||||
#
|
||||
# This tool's primary use is for creating an error status table used
|
||||
# by errPrint, and errSymLookup.
|
||||
#
|
||||
# FILES
|
||||
# errMdef.h Module number file for each h directory
|
||||
# errSymTbl.c Source file generated by tool in the cwd
|
||||
#
|
||||
# SEE ALSO: errnoLib(1), symLib(1)
|
||||
|
||||
use strict;
|
||||
use Getopt::Std;
|
||||
|
||||
my $tool = 'makeStatTbl.pl';
|
||||
|
||||
our ($opt_h);
|
||||
our $opt_o = 'errSymTbl.c';
|
||||
|
||||
$Getopt::Std::OUTPUT_HELP_VERSION = 1;
|
||||
|
||||
&HELP_MESSAGE unless getopts('ho:') && @ARGV;
|
||||
&HELP_MESSAGE if $opt_h;
|
||||
|
||||
my (@syms, %vals, %msgs);
|
||||
|
||||
# Extract names, values and comments from all S_ and M_ symbol definitions
|
||||
while (<>) {
|
||||
chomp;
|
||||
next unless m/^ \s* \# \s* define \s+ ([SM]_[A-Za-z0-9_]+)
|
||||
\s+ (.*?) \s* \/ \* \s* (.*?) \s* \* \/ \s* $/x;
|
||||
push @syms, $1;
|
||||
$vals{$1} = $2;
|
||||
$msgs{$1} = $3;
|
||||
}
|
||||
|
||||
open my $out, '>', $opt_o or
|
||||
die "Can't create $opt_o: $!\n";
|
||||
|
||||
print $out <<"END";
|
||||
/* Generated file $opt_o */
|
||||
|
||||
#include "errMdef.h"
|
||||
#include "errSymTbl.h"
|
||||
#include "dbDefs.h"
|
||||
|
||||
END
|
||||
|
||||
my @mods = grep {/^M_/} @syms;
|
||||
my @errs = grep {/^S_/} @syms;
|
||||
|
||||
foreach my $mod (@mods) {
|
||||
my $val = $vals{$mod};
|
||||
my $msg = $msgs{$mod};
|
||||
print $out
|
||||
"#ifndef $mod\n",
|
||||
"#define $mod $val /* $msg */\n",
|
||||
"#endif\n";
|
||||
}
|
||||
|
||||
print $out
|
||||
"\n",
|
||||
"static ERRSYMBOL symbols[] = {\n";
|
||||
|
||||
foreach my $err (@errs) {
|
||||
my $msg = escape($msgs{$err});
|
||||
my $val = $vals{$err};
|
||||
print $out
|
||||
" { $val, \"$msg\"},\n";
|
||||
}
|
||||
|
||||
print $out <<"END";
|
||||
};
|
||||
|
||||
static ERRSYMTAB symTbl = {
|
||||
NELEMENTS(symbols), symbols
|
||||
};
|
||||
|
||||
ERRSYMTAB_ID errSymTbl = &symTbl;
|
||||
|
||||
END
|
||||
|
||||
sub HELP_MESSAGE {
|
||||
print STDERR "Usage: $tool [-o file.c] files.h ...\n";
|
||||
exit 2;
|
||||
}
|
||||
|
||||
sub escape {
|
||||
$_ = shift;
|
||||
s/"/\\"/g;
|
||||
return $_;
|
||||
}
|
||||
14
modules/libcom/src/fdmgr/Makefile
Normal file
14
modules/libcom/src/fdmgr/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/fdmgr
|
||||
INC += fdManager.h
|
||||
INC += fdmgr.h
|
||||
Com_SRCS += fdmgr.cpp
|
||||
Com_SRCS += fdManager.cpp
|
||||
359
modules/libcom/src/fdmgr/fdManager.cpp
Normal file
359
modules/libcom/src/fdmgr/fdManager.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
//
|
||||
// File descriptor management C++ class library
|
||||
// (for multiplexing IO in a single threaded environment)
|
||||
//
|
||||
// Author Jeffrey O. Hill
|
||||
// johill@lanl.gov
|
||||
// 505 665 1831
|
||||
//
|
||||
// NOTES:
|
||||
// 1) This library is not thread safe
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define instantiateRecourceLib
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsThread.h"
|
||||
#include "fdManager.h"
|
||||
#include "locationException.h"
|
||||
|
||||
using std :: max;
|
||||
|
||||
epicsShareDef fdManager fileDescriptorManager;
|
||||
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
|
||||
//
|
||||
// fdManager::fdManager()
|
||||
//
|
||||
// hopefully its a reasonable guess that select() and epicsThreadSleep()
|
||||
// will have the same sleep quantum
|
||||
//
|
||||
epicsShareFunc fdManager::fdManager () :
|
||||
sleepQuantum ( epicsThreadSleepQuantum () ),
|
||||
fdSetsPtr ( new fd_set [fdrNEnums] ),
|
||||
pTimerQueue ( 0 ), maxFD ( 0 ), processInProg ( false ),
|
||||
pCBReg ( 0 )
|
||||
{
|
||||
int status = osiSockAttach ();
|
||||
assert (status);
|
||||
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fdManager::~fdManager()
|
||||
//
|
||||
epicsShareFunc fdManager::~fdManager()
|
||||
{
|
||||
fdReg *pReg;
|
||||
|
||||
while ( (pReg = this->regList.get()) ) {
|
||||
pReg->state = fdReg::limbo;
|
||||
pReg->destroy();
|
||||
}
|
||||
while ( (pReg = this->activeList.get()) ) {
|
||||
pReg->state = fdReg::limbo;
|
||||
pReg->destroy();
|
||||
}
|
||||
delete this->pTimerQueue;
|
||||
delete [] this->fdSetsPtr;
|
||||
osiSockRelease();
|
||||
}
|
||||
|
||||
//
|
||||
// fdManager::process()
|
||||
//
|
||||
epicsShareFunc void fdManager::process (double delay)
|
||||
{
|
||||
this->lazyInitTimerQueue ();
|
||||
|
||||
//
|
||||
// no recursion
|
||||
//
|
||||
if (this->processInProg) {
|
||||
return;
|
||||
}
|
||||
this->processInProg = true;
|
||||
|
||||
//
|
||||
// One shot at expired timers prior to going into
|
||||
// select. This allows zero delay timers to arm
|
||||
// fd writes. We will never process the timer queue
|
||||
// more than once here so that fd activity get serviced
|
||||
// in a reasonable length of time.
|
||||
//
|
||||
double minDelay = this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
|
||||
if ( minDelay >= delay ) {
|
||||
minDelay = delay;
|
||||
}
|
||||
|
||||
bool ioPending = false;
|
||||
tsDLIter < fdReg > iter = this->regList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
FD_SET(iter->getFD(), &this->fdSetsPtr[iter->getType()]);
|
||||
ioPending = true;
|
||||
++iter;
|
||||
}
|
||||
|
||||
if ( ioPending ) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = static_cast<time_t> ( minDelay );
|
||||
tv.tv_usec = static_cast<long> ( (minDelay-tv.tv_sec) * uSecPerSec );
|
||||
|
||||
fd_set * pReadSet = & this->fdSetsPtr[fdrRead];
|
||||
fd_set * pWriteSet = & this->fdSetsPtr[fdrWrite];
|
||||
fd_set * pExceptSet = & this->fdSetsPtr[fdrException];
|
||||
int status = select (this->maxFD, pReadSet, pWriteSet, pExceptSet, &tv);
|
||||
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
|
||||
if ( status > 0 ) {
|
||||
|
||||
//
|
||||
// Look for activity
|
||||
//
|
||||
iter=this->regList.firstIter ();
|
||||
while ( iter.valid () && status > 0 ) {
|
||||
tsDLIter < fdReg > tmp = iter;
|
||||
tmp++;
|
||||
if (FD_ISSET(iter->getFD(), &this->fdSetsPtr[iter->getType()])) {
|
||||
FD_CLR(iter->getFD(), &this->fdSetsPtr[iter->getType()]);
|
||||
this->regList.remove(*iter);
|
||||
this->activeList.add(*iter);
|
||||
iter->state = fdReg::active;
|
||||
status--;
|
||||
}
|
||||
iter = tmp;
|
||||
}
|
||||
|
||||
//
|
||||
// I am careful to prevent problems if they access the
|
||||
// above list while in a "callBack()" routine
|
||||
//
|
||||
fdReg * pReg;
|
||||
while ( (pReg = this->activeList.get()) ) {
|
||||
pReg->state = fdReg::limbo;
|
||||
|
||||
//
|
||||
// Tag current fdReg so that we
|
||||
// can detect if it was deleted
|
||||
// during the call back
|
||||
//
|
||||
this->pCBReg = pReg;
|
||||
pReg->callBack();
|
||||
if (this->pCBReg != NULL) {
|
||||
//
|
||||
// check only after we see that it is non-null so
|
||||
// that we dont trigger bounds-checker dangling pointer
|
||||
// error
|
||||
//
|
||||
assert (this->pCBReg==pReg);
|
||||
this->pCBReg = 0;
|
||||
if (pReg->onceOnly) {
|
||||
pReg->destroy();
|
||||
}
|
||||
else {
|
||||
this->regList.add(*pReg);
|
||||
pReg->state = fdReg::pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( status < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
|
||||
// dont depend on flags being properly set if
|
||||
// an error is retuned from select
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// print a message if its an unexpected error
|
||||
//
|
||||
if ( errnoCpy != SOCK_EINTR ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
fprintf ( stderr,
|
||||
"fdManager: select failed because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* recover from subtle differences between
|
||||
* windows sockets and UNIX sockets implementation
|
||||
* of select()
|
||||
*/
|
||||
epicsThreadSleep(minDelay);
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
}
|
||||
this->processInProg = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// fdReg::destroy()
|
||||
// (default destroy method)
|
||||
//
|
||||
void fdReg::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
//
|
||||
// fdReg::~fdReg()
|
||||
//
|
||||
fdReg::~fdReg()
|
||||
{
|
||||
this->manager.removeReg(*this);
|
||||
}
|
||||
|
||||
//
|
||||
// fdReg::show()
|
||||
//
|
||||
void fdReg::show(unsigned level) const
|
||||
{
|
||||
printf ("fdReg at %p\n", (void *) this);
|
||||
if (level>1u) {
|
||||
printf ("\tstate = %d, onceOnly = %d\n",
|
||||
this->state, this->onceOnly);
|
||||
}
|
||||
this->fdRegId::show(level);
|
||||
}
|
||||
|
||||
//
|
||||
// fdRegId::show()
|
||||
//
|
||||
void fdRegId::show ( unsigned level ) const
|
||||
{
|
||||
printf ( "fdRegId at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if ( level > 1u ) {
|
||||
printf ( "\tfd = %d, type = %d\n",
|
||||
this->fd, this->type );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fdManager::installReg ()
|
||||
//
|
||||
void fdManager::installReg (fdReg ®)
|
||||
{
|
||||
this->maxFD = max ( this->maxFD, reg.getFD()+1 );
|
||||
// Most applications will find that its important to push here to
|
||||
// the front of the list so that transient writes get executed
|
||||
// first allowing incoming read protocol to find that outgoing
|
||||
// buffer space is newly available.
|
||||
this->regList.push ( reg );
|
||||
reg.state = fdReg::pending;
|
||||
|
||||
int status = this->fdTbl.add ( reg );
|
||||
if ( status != 0 ) {
|
||||
throwWithLocation ( fdInterestSubscriptionAlreadyExits () );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fdManager::removeReg ()
|
||||
//
|
||||
void fdManager::removeReg (fdReg ®In)
|
||||
{
|
||||
fdReg *pItemFound;
|
||||
|
||||
pItemFound = this->fdTbl.remove (regIn);
|
||||
if (pItemFound!=®In) {
|
||||
fprintf(stderr,
|
||||
"fdManager::removeReg() bad fd registration object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// signal fdManager that the fdReg was deleted
|
||||
// during the call back
|
||||
//
|
||||
if (this->pCBReg == ®In) {
|
||||
this->pCBReg = 0;
|
||||
}
|
||||
|
||||
switch (regIn.state) {
|
||||
case fdReg::active:
|
||||
this->activeList.remove (regIn);
|
||||
break;
|
||||
case fdReg::pending:
|
||||
this->regList.remove (regIn);
|
||||
break;
|
||||
case fdReg::limbo:
|
||||
break;
|
||||
default:
|
||||
//
|
||||
// here if memory corrupted
|
||||
//
|
||||
assert(0);
|
||||
}
|
||||
regIn.state = fdReg::limbo;
|
||||
|
||||
FD_CLR(regIn.getFD(), &this->fdSetsPtr[regIn.getType()]);
|
||||
}
|
||||
|
||||
//
|
||||
// fdManager::reschedule ()
|
||||
// NOOP - this only runs single threaded, and therefore they can only
|
||||
// add a new timer from places that will always end up in a reschedule
|
||||
//
|
||||
void fdManager::reschedule ()
|
||||
{
|
||||
}
|
||||
|
||||
double fdManager::quantum ()
|
||||
{
|
||||
return this->sleepQuantum;
|
||||
}
|
||||
|
||||
//
|
||||
// lookUpFD()
|
||||
//
|
||||
epicsShareFunc fdReg *fdManager::lookUpFD (const SOCKET fd, const fdRegType type)
|
||||
{
|
||||
if (fd<0) {
|
||||
return NULL;
|
||||
}
|
||||
fdRegId id (fd,type);
|
||||
return this->fdTbl.lookup(id);
|
||||
}
|
||||
|
||||
//
|
||||
// fdReg::fdReg()
|
||||
//
|
||||
fdReg::fdReg (const SOCKET fdIn, const fdRegType typIn,
|
||||
const bool onceOnlyIn, fdManager &managerIn) :
|
||||
fdRegId (fdIn,typIn), state (limbo),
|
||||
onceOnly (onceOnlyIn), manager (managerIn)
|
||||
{
|
||||
if (!FD_IN_FDSET(fdIn)) {
|
||||
fprintf (stderr, "%s: fd > FD_SETSIZE ignored\n",
|
||||
__FILE__);
|
||||
return;
|
||||
}
|
||||
this->manager.installReg (*this);
|
||||
}
|
||||
|
||||
template class resTable<fdReg, fdRegId>;
|
||||
204
modules/libcom/src/fdmgr/fdManager.h
Normal file
204
modules/libcom/src/fdmgr/fdManager.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* File descriptor management C++ class library
|
||||
* (for multiplexing IO in a single threaded environment)
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef fdManagerH_included
|
||||
#define fdManagerH_included
|
||||
|
||||
#include "shareLib.h" // reset share lib defines
|
||||
#include "tsDLList.h"
|
||||
#include "resourceLib.h"
|
||||
#include "epicsTime.h"
|
||||
#include "osiSock.h"
|
||||
#include "epicsTimer.h"
|
||||
|
||||
enum fdRegType {fdrRead, fdrWrite, fdrException, fdrNEnums};
|
||||
|
||||
//
|
||||
// fdRegId
|
||||
//
|
||||
// file descriptor interest id
|
||||
//
|
||||
class epicsShareClass fdRegId
|
||||
{
|
||||
public:
|
||||
|
||||
fdRegId (const SOCKET fdIn, const fdRegType typeIn) :
|
||||
fd(fdIn), type(typeIn) {}
|
||||
|
||||
SOCKET getFD () const
|
||||
{
|
||||
return this->fd;
|
||||
}
|
||||
|
||||
fdRegType getType () const
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
bool operator == (const fdRegId &idIn) const
|
||||
{
|
||||
return this->fd == idIn.fd && this->type==idIn.type;
|
||||
}
|
||||
|
||||
resTableIndex hash () const;
|
||||
|
||||
virtual void show (unsigned level) const;
|
||||
|
||||
virtual ~fdRegId() {}
|
||||
private:
|
||||
SOCKET fd;
|
||||
fdRegType type;
|
||||
};
|
||||
|
||||
//
|
||||
// fdManager
|
||||
//
|
||||
// file descriptor manager
|
||||
//
|
||||
class fdManager : public epicsTimerQueueNotify {
|
||||
public:
|
||||
//
|
||||
// exceptions
|
||||
//
|
||||
class fdInterestSubscriptionAlreadyExits {};
|
||||
|
||||
epicsShareFunc fdManager ();
|
||||
epicsShareFunc virtual ~fdManager ();
|
||||
epicsShareFunc void process ( double delay ); // delay parameter is in seconds
|
||||
|
||||
// returns NULL if the fd is unknown
|
||||
epicsShareFunc class fdReg *lookUpFD (const SOCKET fd, const fdRegType type);
|
||||
|
||||
epicsTimer & createTimer ();
|
||||
|
||||
private:
|
||||
tsDLList < fdReg > regList;
|
||||
tsDLList < fdReg > activeList;
|
||||
resTable < fdReg, fdRegId > fdTbl;
|
||||
const double sleepQuantum;
|
||||
fd_set * fdSetsPtr;
|
||||
epicsTimerQueuePassive * pTimerQueue;
|
||||
SOCKET maxFD;
|
||||
bool processInProg;
|
||||
//
|
||||
// Set to fdreg when in call back
|
||||
// and nill otherwise
|
||||
//
|
||||
fdReg * pCBReg;
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
void installReg (fdReg ®);
|
||||
void removeReg (fdReg ®);
|
||||
void lazyInitTimerQueue ();
|
||||
fdManager ( const fdManager & );
|
||||
fdManager & operator = ( const fdManager & );
|
||||
friend class fdReg;
|
||||
};
|
||||
|
||||
//
|
||||
// default file descriptor manager
|
||||
//
|
||||
epicsShareExtern fdManager fileDescriptorManager;
|
||||
|
||||
//
|
||||
// fdReg
|
||||
//
|
||||
// file descriptor registration
|
||||
//
|
||||
class epicsShareClass fdReg :
|
||||
public fdRegId, public tsDLNode<fdReg>, public tsSLNode<fdReg> {
|
||||
friend class fdManager;
|
||||
|
||||
public:
|
||||
|
||||
fdReg (const SOCKET fdIn, const fdRegType type,
|
||||
const bool onceOnly=false, fdManager &manager = fileDescriptorManager);
|
||||
virtual ~fdReg ();
|
||||
|
||||
virtual void show (unsigned level) const;
|
||||
|
||||
//
|
||||
// Called by the file descriptor manager:
|
||||
// 1) If the fdManager is deleted and there are still
|
||||
// fdReg objects attached
|
||||
// 2) Immediately after calling "callBack()" if
|
||||
// the constructor specified "onceOnly"
|
||||
//
|
||||
// fdReg::destroy() does a "delete this"
|
||||
//
|
||||
virtual void destroy ();
|
||||
|
||||
private:
|
||||
enum state {active, pending, limbo};
|
||||
|
||||
//
|
||||
// called when there is activity on the fd
|
||||
// NOTES
|
||||
// 1) the fdManager will call this only once during the
|
||||
// lifetime of a fdReg object if the constructor
|
||||
// specified "onceOnly"
|
||||
//
|
||||
virtual void callBack ()=0;
|
||||
|
||||
unsigned char state; // state enums go here
|
||||
unsigned char onceOnly;
|
||||
fdManager &manager;
|
||||
|
||||
fdReg ( const fdReg & );
|
||||
fdReg & operator = ( const fdReg & );
|
||||
};
|
||||
|
||||
//
|
||||
// fdRegId::hash()
|
||||
//
|
||||
inline resTableIndex fdRegId::hash () const
|
||||
{
|
||||
const unsigned fdManagerHashTableMinIndexBits = 8;
|
||||
const unsigned fdManagerHashTableMaxIndexBits = sizeof(SOCKET)*CHAR_BIT;
|
||||
resTableIndex hashid;
|
||||
|
||||
hashid = integerHash ( fdManagerHashTableMinIndexBits,
|
||||
fdManagerHashTableMaxIndexBits, this->fd );
|
||||
|
||||
//
|
||||
// also evenly distribute based on the type of fdRegType
|
||||
//
|
||||
hashid ^= this->type;
|
||||
|
||||
//
|
||||
// the result here is always masked to the
|
||||
// proper size after it is returned to the resource class
|
||||
//
|
||||
return hashid;
|
||||
}
|
||||
|
||||
inline void fdManager::lazyInitTimerQueue ()
|
||||
{
|
||||
if ( ! this->pTimerQueue ) {
|
||||
this->pTimerQueue = & epicsTimerQueuePassive::create ( *this );
|
||||
}
|
||||
}
|
||||
|
||||
inline epicsTimer & fdManager::createTimer ()
|
||||
{
|
||||
this->lazyInitTimerQueue ();
|
||||
return this->pTimerQueue->createTimer ();
|
||||
}
|
||||
|
||||
#endif // fdManagerH_included
|
||||
|
||||
336
modules/libcom/src/fdmgr/fdmgr.cpp
Normal file
336
modules/libcom/src/fdmgr/fdmgr.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
//
|
||||
// File descriptor management C++ class library
|
||||
// (for multiplexing IO in a single threaded environment)
|
||||
//
|
||||
// Author Jeffrey O. Hill
|
||||
// johill@lanl.gov
|
||||
// 505 665 1831
|
||||
//
|
||||
// NOTES:
|
||||
// 1) the routines in this file provide backward compatibility with the original
|
||||
// "C" based file descriptor manager API
|
||||
// 2) This library is _not_ thread safe
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include "locationException.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "fdManager.h"
|
||||
#include "fdmgr.h"
|
||||
|
||||
static const fdRegType fdiToFdRegType[] = {fdrRead, fdrWrite, fdrException};
|
||||
static const unsigned fdiToFdRegTypeNElements = sizeof (fdiToFdRegType) / sizeof (fdiToFdRegType[0]);
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
|
||||
class fdRegForOldFdmgr : public fdReg {
|
||||
public:
|
||||
//
|
||||
// exceptions
|
||||
//
|
||||
class noFunctionSpecified {};
|
||||
class doubleDelete {};
|
||||
|
||||
epicsShareFunc fdRegForOldFdmgr (const SOCKET fdIn, const fdRegType type,
|
||||
const bool onceOnly, fdManager &manager, pCallBackFDMgr pFunc, void *pParam);
|
||||
epicsShareFunc ~fdRegForOldFdmgr ();
|
||||
|
||||
private:
|
||||
pCallBackFDMgr pFunc;
|
||||
void *pParam;
|
||||
epicsShareFunc virtual void callBack ();
|
||||
fdRegForOldFdmgr ( const fdRegForOldFdmgr & );
|
||||
fdRegForOldFdmgr & operator = ( const fdRegForOldFdmgr & );
|
||||
};
|
||||
|
||||
class oldFdmgr;
|
||||
|
||||
//
|
||||
// timerForOldFdmgr
|
||||
//
|
||||
class timerForOldFdmgr : public epicsTimerNotify, public chronIntIdRes<timerForOldFdmgr> {
|
||||
public:
|
||||
epicsShareFunc timerForOldFdmgr (oldFdmgr &fdmgr, double delay, pCallBackFDMgr pFunc, void *pParam);
|
||||
epicsShareFunc virtual ~timerForOldFdmgr ();
|
||||
|
||||
//
|
||||
// exceptions
|
||||
//
|
||||
class noFunctionSpecified {};
|
||||
class doubleDelete {};
|
||||
private:
|
||||
epicsTimer &timer;
|
||||
oldFdmgr &fdmgr;
|
||||
pCallBackFDMgr pFunc;
|
||||
void *pParam;
|
||||
unsigned id;
|
||||
epicsShareFunc expireStatus expire ( const epicsTime & currentTime );
|
||||
timerForOldFdmgr ( const timerForOldFdmgr & );
|
||||
timerForOldFdmgr & operator = ( const timerForOldFdmgr & );
|
||||
};
|
||||
|
||||
class oldFdmgr : public fdManager {
|
||||
friend class timerForOldFdmgr;
|
||||
friend epicsShareFunc int epicsShareAPI fdmgr_clear_timeout (fdctx *pfdctx, fdmgrAlarmId id);
|
||||
|
||||
public:
|
||||
oldFdmgr ();
|
||||
|
||||
private:
|
||||
chronIntIdResTable <timerForOldFdmgr> resTbl;
|
||||
oldFdmgr ( const oldFdmgr & );
|
||||
oldFdmgr & operator = ( const oldFdmgr & );
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class chronIntIdResTable <timerForOldFdmgr>;
|
||||
template class resTable<timerForOldFdmgr, chronIntId>;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
|
||||
epicsShareFunc fdRegForOldFdmgr::fdRegForOldFdmgr
|
||||
(const SOCKET fdIn, const fdRegType typeIn,
|
||||
const bool onceOnlyIn, fdManager &managerIn,
|
||||
pCallBackFDMgr pFuncIn, void *pParamIn) :
|
||||
fdReg (fdIn, typeIn, onceOnlyIn, managerIn),
|
||||
pFunc (pFuncIn), pParam (pParamIn)
|
||||
{
|
||||
if (pFuncIn==NULL) {
|
||||
throwWithLocation ( noFunctionSpecified () );
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc fdRegForOldFdmgr::~fdRegForOldFdmgr ()
|
||||
{
|
||||
if (this->pFunc==NULL) {
|
||||
throwWithLocation ( doubleDelete () );
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc void fdRegForOldFdmgr::callBack ()
|
||||
{
|
||||
(*this->pFunc) (this->pParam);
|
||||
}
|
||||
|
||||
timerForOldFdmgr::timerForOldFdmgr ( oldFdmgr &fdmgrIn,
|
||||
double delayIn, pCallBackFDMgr pFuncIn, void * pParamIn ) :
|
||||
timer ( fdmgrIn.createTimer() ),
|
||||
fdmgr ( fdmgrIn ), pFunc ( pFuncIn ), pParam( pParamIn )
|
||||
{
|
||||
if ( pFuncIn == NULL ) {
|
||||
throwWithLocation ( noFunctionSpecified () );
|
||||
}
|
||||
this->fdmgr.resTbl.idAssignAdd (*this);
|
||||
this->timer.start ( *this, delayIn );
|
||||
}
|
||||
|
||||
timerForOldFdmgr::~timerForOldFdmgr ()
|
||||
{
|
||||
this->fdmgr.resTbl.remove ( this->getId() );
|
||||
this->timer.destroy ();
|
||||
}
|
||||
|
||||
epicsTimerNotify::expireStatus timerForOldFdmgr::expire ( const epicsTime & )
|
||||
{
|
||||
(*this->pFunc) (this->pParam);
|
||||
return noRestart;
|
||||
}
|
||||
|
||||
oldFdmgr::oldFdmgr () {}
|
||||
|
||||
extern "C" epicsShareFunc fdctx * epicsShareAPI fdmgr_init (void)
|
||||
{
|
||||
oldFdmgr *pfdm;
|
||||
|
||||
try {
|
||||
pfdm = new oldFdmgr();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pfdm = NULL;
|
||||
}
|
||||
|
||||
return (fdctx *) pfdm;
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc fdmgrAlarmId epicsShareAPI fdmgr_add_timeout (
|
||||
fdctx *pfdctx, struct timeval *ptimeout, pCallBackFDMgr pFunc, void *pParam)
|
||||
{
|
||||
double delay = ptimeout->tv_sec + ptimeout->tv_usec / static_cast <const double> (uSecPerSec);
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
timerForOldFdmgr *pTimer;
|
||||
unsigned id = fdmgrNoAlarm;
|
||||
|
||||
if (!pfdm) {
|
||||
return fdmgrNoAlarm;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
pTimer = new timerForOldFdmgr
|
||||
(*pfdm, delay, pFunc, pParam);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pTimer = NULL;
|
||||
}
|
||||
if (pTimer) {
|
||||
id = pTimer->getId ();
|
||||
if (id!=fdmgrNoAlarm) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
delete pTimer;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_clear_timeout (fdctx *pfdctx, fdmgrAlarmId id)
|
||||
{
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
timerForOldFdmgr *pTimer;
|
||||
|
||||
try {
|
||||
pTimer = pfdm->resTbl.remove (id);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pTimer = NULL;
|
||||
}
|
||||
|
||||
if (pTimer==NULL) {
|
||||
return -1;
|
||||
}
|
||||
delete pTimer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_add_callback (
|
||||
fdctx *pfdctx, SOCKET fd, enum fdi_type fdi, pCallBackFDMgr pFunc, void *pParam)
|
||||
{
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
fdRegForOldFdmgr *pfdrbc;
|
||||
bool onceOnly = (fdi==fdi_write);
|
||||
unsigned fdiType;
|
||||
|
||||
if (pfdm==NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pFunc==NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fdi<0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdiType = (unsigned) fdi;
|
||||
|
||||
if (fdiType>=fdiToFdRegTypeNElements) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
pfdrbc = new fdRegForOldFdmgr (fd, fdiToFdRegType[fdiType], onceOnly, *pfdm, pFunc, pParam);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pfdrbc = NULL;
|
||||
}
|
||||
|
||||
if (pfdrbc==NULL) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_clear_callback (
|
||||
fdctx *pfdctx, SOCKET fd, enum fdi_type fdi)
|
||||
{
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
fdReg *pFDR;
|
||||
|
||||
if (pfdm==NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
pFDR = pfdm->lookUpFD (fd, fdiToFdRegType[fdi]);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pFDR = NULL;
|
||||
}
|
||||
|
||||
if (pFDR==NULL) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
delete pFDR;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_pend_event (fdctx *pfdctx, struct timeval *ptimeout)
|
||||
{
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
double delay = ptimeout->tv_sec + ptimeout->tv_usec / static_cast <const double> (uSecPerSec);
|
||||
|
||||
try {
|
||||
pfdm->process (delay);
|
||||
}
|
||||
catch (...) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_delete (fdctx *pfdctx)
|
||||
{
|
||||
oldFdmgr *pfdm = static_cast <oldFdmgr *> (pfdctx);
|
||||
delete pfdm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* depricated interface
|
||||
*/
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_clear_fd (fdctx *pfdctx, SOCKET fd)
|
||||
{
|
||||
return fdmgr_clear_callback(pfdctx, fd, fdi_read);
|
||||
}
|
||||
|
||||
/*
|
||||
* depricated interface
|
||||
*/
|
||||
extern "C" epicsShareFunc int epicsShareAPI fdmgr_add_fd (
|
||||
fdctx *pfdctx, SOCKET fd, void (*pfunc)(void *pParam), void *param)
|
||||
{
|
||||
return fdmgr_add_callback (pfdctx, fd, fdi_read, pfunc, param);
|
||||
}
|
||||
169
modules/libcom/src/fdmgr/fdmgr.h
Normal file
169
modules/libcom/src/fdmgr/fdmgr.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* fdmgr.h
|
||||
*
|
||||
* Header file associated with a file descriptor manager
|
||||
* for use with the UNIX system call select
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* hill@atdiv.lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef includeFdmgrH
|
||||
#define includeFdmgrH
|
||||
|
||||
#include "ellLib.h"
|
||||
#include "bucketLib.h"
|
||||
#include "osiSock.h"
|
||||
#include "epicsThread.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum fdi_type {fdi_read, fdi_write, fdi_excp};
|
||||
enum alarm_list_type {alt_invalid, alt_alarm, alt_expired, alt_free};
|
||||
|
||||
typedef void fdctx;
|
||||
typedef void (*pCallBackFDMgr)(void *);
|
||||
|
||||
/*
|
||||
* C "typedef" name "alarm" was changed to "fdmgrAlarm" to avoid collisions
|
||||
* with other libraries. Next the identifier was changed again to
|
||||
* an unsigned integer type "fdmgrAlarmId".
|
||||
*
|
||||
* This "#define" is for codes that used to use a pointer to the old typedef
|
||||
* "alarm" or "fdmgrAlarm" types to identify an alarm.
|
||||
*
|
||||
* ie the following code will allow compilation against
|
||||
* all versions:
|
||||
*
|
||||
* #if defined (NEW_FDMGR_ALARMID)
|
||||
* fdmgrAlarmId XXXX
|
||||
* #elif defined (NEW_FDMGR_ALARM)
|
||||
* fdmgrAlarm *XXXX;
|
||||
* #else
|
||||
* alarm *XXXX;
|
||||
* #endif
|
||||
*
|
||||
* XXXX = fdmgrAlarmId fdmgr_add_timeout()
|
||||
*/
|
||||
typedef unsigned fdmgrAlarmId;
|
||||
#define NEW_FDMGR_ALARMID
|
||||
|
||||
/*
|
||||
*
|
||||
* Initialize a file descriptor manager session
|
||||
*
|
||||
*/
|
||||
epicsShareFunc fdctx * epicsShareAPI fdmgr_init(void);
|
||||
|
||||
/*
|
||||
* Specify a function to be called with a specified parameter
|
||||
* after a specified delay relative to the current time
|
||||
*
|
||||
* Returns fdmgrNoAlarm (zero) if alarm cant be created
|
||||
*/
|
||||
#define fdmgrNoAlarm 0
|
||||
epicsShareFunc fdmgrAlarmId epicsShareAPI fdmgr_add_timeout(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
struct timeval *ptimeout, /* relative delay from current time */
|
||||
pCallBackFDMgr pfunc, /* function (handler) to call */
|
||||
void *param /* first parameter passed to the func */
|
||||
);
|
||||
|
||||
/*
|
||||
* Clear a timeout which has not executed its function (handler)
|
||||
* yet.
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_clear_timeout(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
fdmgrAlarmId id /* alarm to delete */
|
||||
);
|
||||
|
||||
/*
|
||||
*
|
||||
* Specify a function (handler) to be called with a specified parameter
|
||||
* when a file descriptor becomes active. The parameter fdi (file
|
||||
* descriptor interest) specifies the type of activity (IO) we wish
|
||||
* to be informed of: read, write, or exception. For more
|
||||
* info on this see the man pages for the UNIX system call select().
|
||||
*
|
||||
* read and exception callbacks are permanent( ie the application's
|
||||
* function (handler) continues to be called each time the
|
||||
* file descriptor becomes active until fdmgr_add_callback()
|
||||
* is called).
|
||||
*
|
||||
* write callbacks are called only once after each call to
|
||||
* fdmgr_add_callback()
|
||||
*
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_add_callback(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
SOCKET fd, /* file descriptor */
|
||||
enum fdi_type fdi, /* file descriptor interest type */
|
||||
pCallBackFDMgr pfunc, /* function (handler) to call */
|
||||
void *param /* first parameter passed to the func */
|
||||
);
|
||||
|
||||
/*
|
||||
*
|
||||
* Clear nterest in a type of file descriptor activity (IO).
|
||||
*
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_clear_callback(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
SOCKET fd, /* file descriptor */
|
||||
enum fdi_type fdi /* file descriptor interest type */
|
||||
);
|
||||
|
||||
/*
|
||||
*
|
||||
* Wait a specified delay relative from the current time for file
|
||||
* descriptor activity (IO) or timeouts (timer expiration). Application
|
||||
* specified functions (handlers) will not be called unless the
|
||||
* application waits in this function or polls it frequently
|
||||
* enough.
|
||||
*
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_pend_event(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
struct timeval *ptimeout
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* obsolete interface
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_clear_fd(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
SOCKET fd
|
||||
);
|
||||
|
||||
/*
|
||||
* obsolete interface
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI fdmgr_add_fd(
|
||||
fdctx *pfdctx, /* fd mgr ctx from fdmgr_init() */
|
||||
SOCKET fd,
|
||||
pCallBackFDMgr pfunc, /* function (handler) to call */
|
||||
void *param
|
||||
);
|
||||
|
||||
epicsShareFunc int epicsShareAPI fdmgr_delete(fdctx *pfdctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ifndef includeFdmgrH (last line in this file) */
|
||||
|
||||
38
modules/libcom/src/flex/COPYING
Normal file
38
modules/libcom/src/flex/COPYING
Normal file
@@ -0,0 +1,38 @@
|
||||
Flex carries the copyright used for BSD software, slightly modified
|
||||
because it originated at the Lawrence Berkeley (not Livermore!) Laboratory,
|
||||
which operates under a contract with the Department of Energy:
|
||||
|
||||
Copyright (c) 1990 The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
This code is derived from software contributed to Berkeley by
|
||||
Vern Paxson.
|
||||
|
||||
The United States Government has rights in this work pursuant
|
||||
to contract no. DE-AC03-76SF00098 between the United States
|
||||
Department of Energy and the University of California.
|
||||
|
||||
Redistribution and use in source and binary forms are permitted
|
||||
provided that: (1) source distributions retain this entire
|
||||
copyright notice and comment, and (2) distributions including
|
||||
binaries display the following acknowledgement: ``This product
|
||||
includes software developed by the University of California,
|
||||
Berkeley and its contributors'' in the documentation or other
|
||||
materials provided with the distribution and in all advertising
|
||||
materials mentioning features or use of this software. Neither the
|
||||
name of the University nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE.
|
||||
|
||||
This basically says "do whatever you please with this software except
|
||||
remove this notice or take advantage of the University's (or the flex
|
||||
authors') name".
|
||||
|
||||
Note that the "flex.skel" scanner skeleton carries no copyright notice.
|
||||
You are free to do whatever you please with scanners generated using flex;
|
||||
for them, you are not even bound by the above copyright.
|
||||
345
modules/libcom/src/flex/Changes
Normal file
345
modules/libcom/src/flex/Changes
Normal file
@@ -0,0 +1,345 @@
|
||||
Changes between 2.3 Patch #7 (28Mar91) and 2.3 Patch #6:
|
||||
|
||||
- Fixed out-of-bounds array access that caused bad tables
|
||||
to be produced on machines where the bad reference happened
|
||||
to yield a 1. This caused problems installing or running
|
||||
flex on some Suns, in particular.
|
||||
|
||||
|
||||
Changes between 2.3 Patch #6 (29Aug90) and 2.3 Patch #5:
|
||||
|
||||
- Fixed a serious bug in yymore() which basically made it
|
||||
completely broken. Thanks goes to Jean Christophe of
|
||||
the Nethack development team for finding the problem
|
||||
and passing along the fix.
|
||||
|
||||
|
||||
Changes between 2.3 Patch #5 (16Aug90) and 2.3 Patch #4:
|
||||
|
||||
- An up-to-date version of initscan.c so "make test" will
|
||||
work after applying the previous patches
|
||||
|
||||
|
||||
Changes between 2.3 Patch #4 (14Aug90) and 2.3 Patch #3:
|
||||
|
||||
- Fixed bug in hexadecimal escapes which allowed only digits,
|
||||
not letters, in escapes
|
||||
- Fixed bug in previous "Changes" file!
|
||||
|
||||
|
||||
Changes between 2.3 Patch #3 (03Aug90) and 2.3 Patch #2:
|
||||
|
||||
- Correction to patch #2 for gcc compilation; thanks goes to
|
||||
Paul Eggert for catching this.
|
||||
|
||||
|
||||
Changes between 2.3 Patch #2 (02Aug90) and original 2.3 release:
|
||||
|
||||
- Fixed (hopefully) headaches involving declaring malloc()
|
||||
and free() for gcc, which defines __STDC__ but (often) doesn't
|
||||
come with the standard include files such as <stdlib.h>.
|
||||
Reordered #ifdef maze in the scanner skeleton in the hope of
|
||||
getting the declarations right for cfront and g++, too.
|
||||
|
||||
- Note that this patch supercedes patch #1 for release 2.3,
|
||||
which was never announced but was available briefly for
|
||||
anonymous ftp.
|
||||
|
||||
|
||||
Changes between 2.3 (full) release of 28Jun90 and 2.2 (alpha) release:
|
||||
|
||||
User-visible:
|
||||
|
||||
- A lone <<EOF>> rule (that is, one which is not qualified with
|
||||
a list of start conditions) now specifies the EOF action for
|
||||
*all* start conditions which haven't already had <<EOF>> actions
|
||||
given. To specify an end-of-file action for just the initial
|
||||
state, use <INITIAL><<EOF>>.
|
||||
|
||||
- -d debug output is now contigent on the global yy_flex_debug
|
||||
being set to a non-zero value, which it is by default.
|
||||
|
||||
- A new macro, YY_USER_INIT, is provided for the user to specify
|
||||
initialization action to be taken on the first call to the
|
||||
scanner. This action is done before the scanner does its
|
||||
own initialization.
|
||||
|
||||
- yy_new_buffer() has been added as an alias for yy_create_buffer()
|
||||
|
||||
- Comments beginning with '#' and extending to the end of the line
|
||||
now work, but have been deprecated (in anticipation of making
|
||||
flex recognize #line directives).
|
||||
|
||||
- The funky restrictions on when semi-colons could follow the
|
||||
YY_NEW_FILE and yyless macros have been removed. They now
|
||||
behave identically to functions.
|
||||
|
||||
- A bug in the sample redefinition of YY_INPUT in the documentation
|
||||
has been corrected.
|
||||
|
||||
- A bug in the sample simple tokener in the documentation has
|
||||
been corrected.
|
||||
|
||||
- The documentation on the incompatibilities between flex and
|
||||
lex has been reordered so that the discussion of yylineno
|
||||
and input() come first, as it's anticipated that these will
|
||||
be the most common source of headaches.
|
||||
|
||||
|
||||
Things which didn't used to be documented but now are:
|
||||
|
||||
- flex interprets "^foo|bar" differently from lex. flex interprets
|
||||
it as "match either a 'foo' or a 'bar', providing it comes at the
|
||||
beginning of a line", whereas lex interprets it as "match either
|
||||
a 'foo' at the beginning of a line, or a 'bar' anywhere".
|
||||
|
||||
- flex initializes the global "yyin" on the first call to the
|
||||
scanner, while lex initializes it at compile-time.
|
||||
|
||||
- yy_switch_to_buffer() can be used in the yywrap() macro/routine.
|
||||
|
||||
- flex scanners do not use stdio for their input, and hence when
|
||||
writing an interactive scanner one must explictly call fflush()
|
||||
after writing out a prompt.
|
||||
|
||||
- flex scanner can be made reentrant (after a fashion) by using
|
||||
"yyrestart( yyin );". This is useful for interactive scanners
|
||||
which have interrupt handlers that long-jump out of the scanner.
|
||||
|
||||
- a defense of why yylineno is not supported is included, along
|
||||
with a suggestion on how to convert scanners which rely on it.
|
||||
|
||||
|
||||
Other changes:
|
||||
|
||||
- Prototypes and proper declarations of void routines have
|
||||
been added to the flex source code, courtesy of Kevin B. Kenny.
|
||||
|
||||
- Routines dealing with memory allocation now use void* pointers
|
||||
instead of char* - see Makefile for porting implications.
|
||||
|
||||
- Error-checking is now done when flex closes a file.
|
||||
|
||||
- Various lint tweaks were added to reduce the number of gripes.
|
||||
|
||||
- Makefile has been further parameterized to aid in porting.
|
||||
|
||||
- Support for SCO Unix added.
|
||||
|
||||
- Flex now sports the latest & greatest UC copyright notice
|
||||
(which is only slightly different from the previous one).
|
||||
|
||||
- A note has been added to flexdoc.1 mentioning work in progress
|
||||
on modifying flex to generate straight C code rather than a
|
||||
table-driven automaton, with an email address of whom to contact
|
||||
if you are working along similar lines.
|
||||
|
||||
|
||||
Changes between 2.2 Patch #3 (30Mar90) and 2.2 Patch #2:
|
||||
|
||||
- fixed bug which caused -I scanners to bomb
|
||||
|
||||
|
||||
Changes between 2.2 Patch #2 (27Mar90) and 2.2 Patch #1:
|
||||
|
||||
- fixed bug writing past end of input buffer in yyunput()
|
||||
- fixed bug detecting NUL's at the end of a buffer
|
||||
|
||||
|
||||
Changes between 2.2 Patch #1 (23Mar90) and 2.2 (alpha) release:
|
||||
|
||||
- Makefile fixes: definition of MAKE variable for systems
|
||||
which don't have it; installation of flexdoc.1 along with
|
||||
flex.1; fixed two bugs which could cause "bigtest" to fail.
|
||||
|
||||
- flex.skel fix for compiling with g++.
|
||||
|
||||
- README and flexdoc.1 no longer list an out-of-date BITNET address
|
||||
for contacting me.
|
||||
|
||||
- minor typos and formatting changes to flex.1 and flexdoc.1.
|
||||
|
||||
|
||||
Changes between 2.2 (alpha) release of March '90 and previous release:
|
||||
|
||||
User-visible:
|
||||
|
||||
- Full user documentation now available.
|
||||
|
||||
- Support for 8-bit scanners.
|
||||
|
||||
- Scanners now accept NUL's.
|
||||
|
||||
- A facility has been added for dealing with multiple
|
||||
input buffers.
|
||||
|
||||
- Two manual entries now. One which fully describes flex
|
||||
(rather than just its differences from lex), and the
|
||||
other for quick(er) reference.
|
||||
|
||||
- A number of changes to bring flex closer into compliance
|
||||
with the latest POSIX lex draft:
|
||||
|
||||
%t support
|
||||
flex now accepts multiple input files and concatenates
|
||||
them together to form its input
|
||||
previous -c (compress) flag renamed -C
|
||||
do-nothing -c and -n flags added
|
||||
Any indented code or code within %{}'s in section 2 is
|
||||
now copied to the output
|
||||
|
||||
- yyleng is now a bona fide global integer.
|
||||
|
||||
- -d debug information now gives the line number of the
|
||||
matched rule instead of which number rule it was from
|
||||
the beginning of the file.
|
||||
|
||||
- -v output now includes a summary of the flags used to generate
|
||||
the scanner.
|
||||
|
||||
- unput() and yyrestart() are now globally callable.
|
||||
|
||||
- yyrestart() no longer closes the previous value of yyin.
|
||||
|
||||
- C++ support; generated scanners can be compiled with C++ compiler.
|
||||
|
||||
- Primitive -lfl library added, containing default main()
|
||||
which calls yylex(). A number of routines currently living
|
||||
in the scanner skeleton will probably migrate to here
|
||||
in the future (in particular, yywrap() will probably cease
|
||||
to be a macro and instead be a function in the -lfl library).
|
||||
|
||||
- Hexadecimal (\x) escape sequences added.
|
||||
|
||||
- Support for MS-DOS, VMS, and Turbo-C integrated.
|
||||
|
||||
- The %used/%unused operators have been deprecated. They
|
||||
may go away soon.
|
||||
|
||||
|
||||
Other changes:
|
||||
|
||||
- Makefile enhanced for easier testing and installation.
|
||||
- The parser has been tweaked to detect some erroneous
|
||||
constructions which previously were missed.
|
||||
- Scanner input buffer overflow is now detected.
|
||||
- Bugs with missing "const" declarations fixed.
|
||||
- Out-of-date Minix/Atari patches provided.
|
||||
- Scanners no longer require printf() unless FLEX_DEBUG is being used.
|
||||
- A subtle input() bug has been fixed.
|
||||
- Line numbers for "continued action" rules (those following
|
||||
the special '|' action) are now correct.
|
||||
- unput() bug fixed; had been causing problems porting flex to VMS.
|
||||
- yymore() handling rewritten to fix bug with interaction
|
||||
between yymore() and trailing context.
|
||||
- EOF in actions now generates an error message.
|
||||
- Bug involving -CFe and generating equivalence classes fixed.
|
||||
- Bug which made -CF be treated as -Cf fixed.
|
||||
- Support for SysV tmpnam() added.
|
||||
- Unused #define's for scanner no longer generated.
|
||||
- Error messages which are associated with a particular input
|
||||
line are now all identified with their input line in standard
|
||||
format.
|
||||
- % directives which are valid to lex but not to flex are
|
||||
now ignored instead of generating warnings.
|
||||
- -DSYS_V flag can now also be specified -DUSG for System V
|
||||
compilation.
|
||||
|
||||
|
||||
Changes between 2.1 beta-test release of June '89 and previous release:
|
||||
|
||||
User-visible:
|
||||
|
||||
- -p flag generates a performance report to stderr. The report
|
||||
consists of comments regarding features of the scanner rules
|
||||
which result in slower scanners.
|
||||
|
||||
- -b flag generates backtracking information to lex.backtrack.
|
||||
This is a list of scanner states which require backtracking
|
||||
and the characters on which they do so. By adding rules
|
||||
one can remove backtracking states. If all backtracking states
|
||||
are eliminated, the generated scanner will run faster.
|
||||
Backtracking is not yet documented in the manual entry.
|
||||
|
||||
- Variable trailing context now works, i.e., one can have
|
||||
rules like "(foo)*/[ \t]*bletch". Some trailing context
|
||||
patterns still cannot be properly matched and generate
|
||||
error messages. These are patterns where the ending of the
|
||||
first part of the rule matches the beginning of the second
|
||||
part, such as "zx*/xy*", where the 'x*' matches the 'x' at
|
||||
the beginning of the trailing context. Lex won't get these
|
||||
patterns right either.
|
||||
|
||||
- Faster scanners.
|
||||
|
||||
- End-of-file rules. The special rule "<<EOF>>" indicates
|
||||
actions which are to be taken when an end-of-file is
|
||||
encountered and yywrap() returns non-zero (i.e., indicates
|
||||
no further files to process). See manual entry for example.
|
||||
|
||||
- The -r (reject used) flag is gone. flex now scans the input
|
||||
for occurrences of the string "REJECT" to determine if the
|
||||
action is needed. It tries to be intelligent about this but
|
||||
can be fooled. One can force the presence or absence of
|
||||
REJECT by adding a line in the first section of the form
|
||||
"%used REJECT" or "%unused REJECT".
|
||||
|
||||
- yymore() has been implemented. Similarly to REJECT, flex
|
||||
detects the use of yymore(), which can be overridden using
|
||||
"%used" or "%unused".
|
||||
|
||||
- Patterns like "x{0,3}" now work (i.e., with lower-limit == 0).
|
||||
|
||||
- Removed '\^x' for ctrl-x misfeature.
|
||||
|
||||
- Added '\a' and '\v' escape sequences.
|
||||
|
||||
- \<digits> now works for octal escape sequences; previously
|
||||
\0<digits> was required.
|
||||
|
||||
- Better error reporting; line numbers are associated with rules.
|
||||
|
||||
- yyleng is a macro; it cannot be accessed outside of the
|
||||
scanner source file.
|
||||
|
||||
- yytext and yyleng should not be modified within a flex action.
|
||||
|
||||
- Generated scanners #define the name FLEX_SCANNER.
|
||||
|
||||
- Rules are internally separated by YY_BREAK in lex.yy.c rather
|
||||
than break, to allow redefinition.
|
||||
|
||||
- The macro YY_USER_ACTION can be redefined to provide an action
|
||||
which is always executed prior to the matched rule's action.
|
||||
|
||||
- yyrestart() is a new action which can be used to restart
|
||||
the scanner after it has seen an end-of-file (a "real" one,
|
||||
that is, one for which yywrap() returned non-zero). It takes
|
||||
a FILE* argument indicating a new file to scan and sets
|
||||
things up so that a subsequent call to yylex() will start
|
||||
scanning that file.
|
||||
|
||||
- Internal scanner names all preceded by "yy_"
|
||||
|
||||
- lex.yy.c is deleted if errors are encountered during processing.
|
||||
|
||||
- Comments may be put in the first section of the input by preceding
|
||||
them with '#'.
|
||||
|
||||
|
||||
|
||||
Other changes:
|
||||
|
||||
- Some portability-related bugs fixed, in particular for machines
|
||||
with unsigned characters or sizeof( int* ) != sizeof( int ).
|
||||
Also, tweaks for VMS and Microsoft C (MS-DOS), and identifiers all
|
||||
trimmed to be 31 or fewer characters. Shortened file names
|
||||
for dinosaur OS's. Checks for allocating > 64K memory
|
||||
on 16 bit'ers. Amiga tweaks. Compiles using gcc on a Sun-3.
|
||||
- Compressed and fast scanner skeletons merged.
|
||||
- Skeleton header files done away with.
|
||||
- Generated scanner uses prototypes and "const" for __STDC__.
|
||||
- -DSV flag is now -DSYS_V for System V compilation.
|
||||
- Removed all references to FTL language.
|
||||
- Software now covered by BSD Copyright.
|
||||
- flex will replace lex in subsequent BSD releases.
|
||||
32
modules/libcom/src/flex/EPICS_READ_THIS
Normal file
32
modules/libcom/src/flex/EPICS_READ_THIS
Normal file
@@ -0,0 +1,32 @@
|
||||
This is a version of the BSD flex that has had its skeleton file munged in
|
||||
order to force it to build lex programs that have all their functions and
|
||||
variables defined as static.
|
||||
|
||||
The file flex.skel.static is simply a copy of flex.skel that has been altered
|
||||
to make all the components into static variables.
|
||||
|
||||
In order to be able to actually use the lex files produced by this flavor of
|
||||
flex, you must #include them into your C programs. Otherwise they will
|
||||
be uncallable (all functions are static). This is typical of lex programs
|
||||
that are used by yacc programs anyway.
|
||||
|
||||
The scan.c file is actually the output of scan.l.DISTRIB when run through
|
||||
itself, using the regular flex.skel skeleton with the -i option.
|
||||
|
||||
To regenerate scan.c, make sure you have a build of a working e_flex binary
|
||||
somewhere, then in this directory (not an O.<arch> build directory):
|
||||
|
||||
% mv scan.l.DISTRIB scan.l
|
||||
% /path/to/e_flex -Sflex.skel -8 -i scan.l
|
||||
% mv lex.yy.c scan.c
|
||||
% make
|
||||
|
||||
Then use the new binary to make sure it can build itself:
|
||||
|
||||
% O.<arch>/e_flex -Sflex.skel -8 -i scan.l
|
||||
% mv lex.yy.c scan.c
|
||||
% make
|
||||
|
||||
If that succeeds, don't forget to rename scan.l back again:
|
||||
|
||||
% mv scan.l scan.l.DISTRIB
|
||||
1792
modules/libcom/src/flex/Flex.doc
Normal file
1792
modules/libcom/src/flex/Flex.doc
Normal file
File diff suppressed because it is too large
Load Diff
36
modules/libcom/src/flex/Makefile
Normal file
36
modules/libcom/src/flex/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/flex
|
||||
|
||||
parse_YACCOPT = -l -d
|
||||
|
||||
SKELETON_FILE = flex.skel.static
|
||||
|
||||
parse_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE)
|
||||
|
||||
INC += flex.skel.static
|
||||
|
||||
# flex.c is included in parse.c
|
||||
e_flex_SRCS += ccl.c
|
||||
e_flex_SRCS += dfa.c
|
||||
e_flex_SRCS += ecs.c
|
||||
e_flex_SRCS += gen.c
|
||||
e_flex_SRCS += misc.c
|
||||
e_flex_SRCS += nfa.c
|
||||
e_flex_SRCS += sym.c
|
||||
e_flex_SRCS += tblcmp.c
|
||||
e_flex_SRCS += parse.c
|
||||
e_flex_OBJS += epicsTempFile$(OBJ)
|
||||
|
||||
PROD_HOST += e_flex
|
||||
|
||||
CLEANS += parse.c parse.h
|
||||
76
modules/libcom/src/flex/README
Normal file
76
modules/libcom/src/flex/README
Normal file
@@ -0,0 +1,76 @@
|
||||
This is release 2.3 of flex - a full release.
|
||||
|
||||
The flex distribution consists of the following files:
|
||||
|
||||
README This message
|
||||
|
||||
Makefile
|
||||
flexdef.h
|
||||
parse.y
|
||||
scan.l
|
||||
ccl.c
|
||||
dfa.c
|
||||
ecs.c flex sources
|
||||
gen.c
|
||||
main.c
|
||||
misc.c
|
||||
nfa.c
|
||||
sym.c
|
||||
tblcmp.c
|
||||
yylex.c
|
||||
|
||||
libmain.c flex library (-lfl) source
|
||||
|
||||
initscan.c pre-flex'd version of scan.l
|
||||
|
||||
flex.skel skeleton for generated scanners
|
||||
|
||||
flexdoc.1 full user documentation
|
||||
flex.1 reference documentation
|
||||
|
||||
Changes Differences between this release and the previous one
|
||||
|
||||
COPYING flex's copyright
|
||||
|
||||
MISC/ a directory containing miscellaneous porting-related
|
||||
notes (for Atari, MS-DOS, Turbo-C, and VMS)
|
||||
|
||||
|
||||
Decide where you want to keep flex.skel (suggestion: /usr/local/lib),
|
||||
but don't move it there yet. Edit "Makefile" and change the definition
|
||||
of SKELETON_FILE to reflect the full pathname of flex.skel.
|
||||
|
||||
Read the "Porting considerations" note in the Makefile and make
|
||||
the necessary changes.
|
||||
|
||||
To make flex for the first time, use:
|
||||
|
||||
make first_flex
|
||||
|
||||
which uses the pre-generated copy of the flex scanner (the scanner
|
||||
itself is written using flex).
|
||||
|
||||
Assuming it builds successfully, you can test it using
|
||||
|
||||
make test
|
||||
|
||||
The "diff" should not show any differences.
|
||||
|
||||
If you're feeling adventurous, issue "make bigtest" and be prepared
|
||||
to wait a while.
|
||||
|
||||
Install flex using:
|
||||
|
||||
make install
|
||||
|
||||
|
||||
Please send problems and feedback to:
|
||||
|
||||
vern@cs.cornell.edu
|
||||
decvax!cornell!vern
|
||||
|
||||
Vern Paxson
|
||||
CS Department
|
||||
4126 Upson Hall
|
||||
Cornell University
|
||||
Ithaca, NY 14853-7501
|
||||
13
modules/libcom/src/flex/RULES
Normal file
13
modules/libcom/src/flex/RULES
Normal file
@@ -0,0 +1,13 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
# Ensure that the lexer is built before it is needed
|
||||
parse.c: $(INSTALL_HOST_BIN)/antelope$(HOSTEXE)
|
||||
169
modules/libcom/src/flex/ccl.c
Normal file
169
modules/libcom/src/flex/ccl.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* ccl - routines for character classes */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Vern Paxson.
|
||||
*
|
||||
* The United States Government has rights in this work pursuant
|
||||
* to contract no. DE-AC03-76SF00098 between the United States
|
||||
* Department of Energy and the University of California.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted provided
|
||||
* that: (1) source distributions retain this entire copyright notice and
|
||||
* comment, and (2) distributions including binaries display the following
|
||||
* acknowledgement: ``This product includes software developed by the
|
||||
* University of California, Berkeley and its contributors'' in the
|
||||
* documentation or other materials provided with the distribution and in
|
||||
* all advertising materials mentioning features or use of this software.
|
||||
* Neither the name of the University nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include "flexdef.h"
|
||||
|
||||
/* ccladd - add a single character to a ccl
|
||||
*
|
||||
* synopsis
|
||||
* int cclp;
|
||||
* int ch;
|
||||
* ccladd( cclp, ch );
|
||||
*/
|
||||
|
||||
void ccladd(int cclp, int ch)
|
||||
{
|
||||
int ind, len, newpos, i;
|
||||
|
||||
len = ccllen[cclp];
|
||||
ind = cclmap[cclp];
|
||||
|
||||
/* check to see if the character is already in the ccl */
|
||||
|
||||
for ( i = 0; i < len; ++i )
|
||||
if ( ccltbl[ind + i] == ch )
|
||||
return;
|
||||
|
||||
newpos = ind + len;
|
||||
|
||||
if ( newpos >= current_max_ccl_tbl_size )
|
||||
{
|
||||
current_max_ccl_tbl_size += MAX_CCL_TBL_SIZE_INCREMENT;
|
||||
|
||||
++num_reallocs;
|
||||
|
||||
ccltbl = reallocate_character_array( ccltbl, current_max_ccl_tbl_size );
|
||||
}
|
||||
|
||||
ccllen[cclp] = len + 1;
|
||||
ccltbl[newpos] = ch;
|
||||
}
|
||||
|
||||
|
||||
/* cclinit - make an empty ccl
|
||||
*
|
||||
* synopsis
|
||||
* int cclinit();
|
||||
* new_ccl = cclinit();
|
||||
*/
|
||||
|
||||
int cclinit(void)
|
||||
{
|
||||
if ( ++lastccl >= current_maxccls )
|
||||
{
|
||||
current_maxccls += MAX_CCLS_INCREMENT;
|
||||
|
||||
++num_reallocs;
|
||||
|
||||
cclmap = reallocate_integer_array( cclmap, current_maxccls );
|
||||
ccllen = reallocate_integer_array( ccllen, current_maxccls );
|
||||
cclng = reallocate_integer_array( cclng, current_maxccls );
|
||||
}
|
||||
|
||||
if ( lastccl == 1 )
|
||||
/* we're making the first ccl */
|
||||
cclmap[lastccl] = 0;
|
||||
|
||||
else
|
||||
/* the new pointer is just past the end of the last ccl. Since
|
||||
* the cclmap points to the \first/ character of a ccl, adding the
|
||||
* length of the ccl to the cclmap pointer will produce a cursor
|
||||
* to the first free space
|
||||
*/
|
||||
cclmap[lastccl] = cclmap[lastccl - 1] + ccllen[lastccl - 1];
|
||||
|
||||
ccllen[lastccl] = 0;
|
||||
cclng[lastccl] = 0; /* ccl's start out life un-negated */
|
||||
|
||||
return ( lastccl );
|
||||
}
|
||||
|
||||
|
||||
/* cclnegate - negate a ccl
|
||||
*
|
||||
* synopsis
|
||||
* int cclp;
|
||||
* cclnegate( ccl );
|
||||
*/
|
||||
|
||||
void cclnegate(int cclp)
|
||||
{
|
||||
cclng[cclp] = 1;
|
||||
}
|
||||
|
||||
|
||||
/* list_character_set - list the members of a set of characters in CCL form
|
||||
*
|
||||
* synopsis
|
||||
* int cset[CSIZE];
|
||||
* FILE *file;
|
||||
* list_character_set( cset );
|
||||
*
|
||||
* writes to the given file a character-class representation of those
|
||||
* characters present in the given set. A character is present if it
|
||||
* has a non-zero value in the set array.
|
||||
*/
|
||||
|
||||
void list_character_set(FILE *file, int cset[])
|
||||
{
|
||||
int i;
|
||||
char *readable_form();
|
||||
|
||||
putc( '[', file );
|
||||
|
||||
for ( i = 0; i < csize; ++i )
|
||||
{
|
||||
if ( cset[i] )
|
||||
{
|
||||
int start_char = i;
|
||||
|
||||
putc( ' ', file );
|
||||
|
||||
fputs( readable_form( i ), file );
|
||||
|
||||
while ( ++i < csize && cset[i] )
|
||||
;
|
||||
|
||||
if ( i - 1 > start_char )
|
||||
/* this was a run */
|
||||
fprintf( file, "-%s", readable_form( i - 1 ) );
|
||||
|
||||
putc( ' ', file );
|
||||
}
|
||||
}
|
||||
|
||||
putc( ']', file );
|
||||
}
|
||||
1056
modules/libcom/src/flex/dfa.c
Normal file
1056
modules/libcom/src/flex/dfa.c
Normal file
File diff suppressed because it is too large
Load Diff
342
modules/libcom/src/flex/ecs.c
Normal file
342
modules/libcom/src/flex/ecs.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* ecs - equivalence class routines */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Vern Paxson.
|
||||
*
|
||||
* The United States Government has rights in this work pursuant
|
||||
* to contract no. DE-AC03-76SF00098 between the United States
|
||||
* Department of Energy and the University of California.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted provided
|
||||
* that: (1) source distributions retain this entire copyright notice and
|
||||
* comment, and (2) distributions including binaries display the following
|
||||
* acknowledgement: ``This product includes software developed by the
|
||||
* University of California, Berkeley and its contributors'' in the
|
||||
* documentation or other materials provided with the distribution and in
|
||||
* all advertising materials mentioning features or use of this software.
|
||||
* Neither the name of the University nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include "flexdef.h"
|
||||
|
||||
/* ccl2ecl - convert character classes to set of equivalence classes
|
||||
*
|
||||
* synopsis
|
||||
* ccl2ecl();
|
||||
*/
|
||||
|
||||
void ccl2ecl(void)
|
||||
{
|
||||
int i, ich, newlen, cclp, ccls, cclmec;
|
||||
|
||||
for ( i = 1; i <= lastccl; ++i )
|
||||
{
|
||||
/* we loop through each character class, and for each character
|
||||
* in the class, add the character's equivalence class to the
|
||||
* new "character" class we are creating. Thus when we are all
|
||||
* done, character classes will really consist of collections
|
||||
* of equivalence classes
|
||||
*/
|
||||
|
||||
newlen = 0;
|
||||
cclp = cclmap[i];
|
||||
|
||||
for ( ccls = 0; ccls < ccllen[i]; ++ccls )
|
||||
{
|
||||
ich = ccltbl[cclp + ccls];
|
||||
cclmec = ecgroup[ich];
|
||||
|
||||
if ( xlation && cclmec < 0 )
|
||||
{
|
||||
/* special hack--if we're doing %t tables then it's
|
||||
* possible that no representative of this character's
|
||||
* equivalence class is in the ccl. So waiting till
|
||||
* we see the representative would be disastrous. Instead,
|
||||
* we add this character's equivalence class anyway, if it's
|
||||
* not already present.
|
||||
*/
|
||||
int j;
|
||||
|
||||
/* this loop makes this whole process n^2; but we don't
|
||||
* really care about %t performance anyway
|
||||
*/
|
||||
for ( j = 0; j < newlen; ++j )
|
||||
if ( ccltbl[cclp + j] == -cclmec )
|
||||
break;
|
||||
|
||||
if ( j >= newlen )
|
||||
{ /* no representative yet, add this one in */
|
||||
ccltbl[cclp + newlen] = -cclmec;
|
||||
++newlen;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( cclmec > 0 )
|
||||
{
|
||||
ccltbl[cclp + newlen] = cclmec;
|
||||
++newlen;
|
||||
}
|
||||
}
|
||||
|
||||
ccllen[i] = newlen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cre8ecs - associate equivalence class numbers with class members
|
||||
*
|
||||
* synopsis
|
||||
* int cre8ecs();
|
||||
* number of classes = cre8ecs( fwd, bck, num );
|
||||
*
|
||||
* fwd is the forward linked-list of equivalence class members. bck
|
||||
* is the backward linked-list, and num is the number of class members.
|
||||
*
|
||||
* Returned is the number of classes.
|
||||
*/
|
||||
|
||||
int cre8ecs(int fwd[], int bck[], int num)
|
||||
{
|
||||
int i, j, numcl;
|
||||
|
||||
numcl = 0;
|
||||
|
||||
/* create equivalence class numbers. From now on, abs( bck(x) )
|
||||
* is the equivalence class number for object x. If bck(x)
|
||||
* is positive, then x is the representative of its equivalence
|
||||
* class.
|
||||
*/
|
||||
for ( i = 1; i <= num; ++i )
|
||||
if ( bck[i] == NIL )
|
||||
{
|
||||
bck[i] = ++numcl;
|
||||
for ( j = fwd[i]; j != NIL; j = fwd[j] )
|
||||
bck[j] = -numcl;
|
||||
}
|
||||
|
||||
return ( numcl );
|
||||
}
|
||||
|
||||
|
||||
/* ecs_from_xlation - associate equivalence class numbers using %t table
|
||||
*
|
||||
* synopsis
|
||||
* numecs = ecs_from_xlation( ecmap );
|
||||
*
|
||||
* Upon return, ecmap will map each character code to its equivalence
|
||||
* class. The mapping will be positive if the character is the representative
|
||||
* of its class, negative otherwise.
|
||||
*
|
||||
* Returns the number of equivalence classes used.
|
||||
*/
|
||||
|
||||
int ecs_from_xlation(int ecmap[])
|
||||
{
|
||||
int i;
|
||||
int nul_is_alone = false;
|
||||
int did_default_xlation_class = false;
|
||||
|
||||
if ( xlation[0] != 0 )
|
||||
{
|
||||
/* if NUL shares its translation with other characters, choose one
|
||||
* of the other characters as the representative for the equivalence
|
||||
* class. This allows a cheap test later to see whether we can
|
||||
* do away with NUL's equivalence class.
|
||||
*/
|
||||
for ( i = 1; i < csize; ++i )
|
||||
if ( xlation[i] == -xlation[0] )
|
||||
{
|
||||
xlation[i] = xlation[0];
|
||||
ecmap[0] = -xlation[0];
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i >= csize )
|
||||
/* didn't find a companion character--remember this fact */
|
||||
nul_is_alone = true;
|
||||
}
|
||||
|
||||
for ( i = 1; i < csize; ++i )
|
||||
if ( xlation[i] == 0 )
|
||||
{
|
||||
if ( did_default_xlation_class )
|
||||
ecmap[i] = -num_xlations;
|
||||
|
||||
else
|
||||
{
|
||||
/* make an equivalence class for those characters not
|
||||
* specified in the %t table
|
||||
*/
|
||||
++num_xlations;
|
||||
ecmap[i] = num_xlations;
|
||||
did_default_xlation_class = true;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
ecmap[i] = xlation[i];
|
||||
|
||||
if ( nul_is_alone )
|
||||
/* force NUL's equivalence class to be the last one */
|
||||
{
|
||||
++num_xlations;
|
||||
ecmap[0] = num_xlations;
|
||||
|
||||
/* there's actually a bug here: if someone is fanatic enough to
|
||||
* put every character in its own translation class, then right
|
||||
* now we just promoted NUL's equivalence class to be csize + 1;
|
||||
* we can handle NUL's class number being == csize (by instead
|
||||
* putting it in its own table), but we can't handle some *other*
|
||||
* character having to be put in its own table, too. So in
|
||||
* this case we bail out.
|
||||
*/
|
||||
if ( num_xlations > csize )
|
||||
flexfatal( "too many %t classes!" );
|
||||
}
|
||||
|
||||
return num_xlations;
|
||||
}
|
||||
|
||||
|
||||
/* mkeccl - update equivalence classes based on character class xtions
|
||||
*
|
||||
* synopsis
|
||||
* Char ccls[];
|
||||
* int lenccl, fwd[llsiz], bck[llsiz], llsiz, NUL_mapping;
|
||||
* mkeccl( ccls, lenccl, fwd, bck, llsiz, NUL_mapping );
|
||||
*
|
||||
* where ccls contains the elements of the character class, lenccl is the
|
||||
* number of elements in the ccl, fwd is the forward link-list of equivalent
|
||||
* characters, bck is the backward link-list, and llsiz size of the link-list
|
||||
*
|
||||
* NUL_mapping is the value which NUL (0) should be mapped to.
|
||||
*/
|
||||
|
||||
void mkeccl(unsigned char ccls[], int lenccl, int fwd[], int bck[], int llsiz, int NUL_mapping)
|
||||
{
|
||||
int cclp, oldec, newec;
|
||||
int cclm, i, j;
|
||||
static unsigned char cclflags[CSIZE]; /* initialized to all '\0' */
|
||||
|
||||
/* note that it doesn't matter whether or not the character class is
|
||||
* negated. The same results will be obtained in either case.
|
||||
*/
|
||||
|
||||
cclp = 0;
|
||||
|
||||
while ( cclp < lenccl )
|
||||
{
|
||||
cclm = ccls[cclp];
|
||||
|
||||
if ( NUL_mapping && cclm == 0 )
|
||||
cclm = NUL_mapping;
|
||||
|
||||
oldec = bck[cclm];
|
||||
newec = cclm;
|
||||
|
||||
j = cclp + 1;
|
||||
|
||||
for ( i = fwd[cclm]; i != NIL && i <= llsiz; i = fwd[i] )
|
||||
{ /* look for the symbol in the character class */
|
||||
for ( ; j < lenccl; ++j )
|
||||
{
|
||||
int ccl_char;
|
||||
|
||||
if ( NUL_mapping && ccls[j] == 0 )
|
||||
ccl_char = NUL_mapping;
|
||||
else
|
||||
ccl_char = ccls[j];
|
||||
|
||||
if ( ccl_char > i )
|
||||
break;
|
||||
|
||||
if ( ccl_char == i && ! cclflags[j] )
|
||||
{
|
||||
/* we found an old companion of cclm in the ccl.
|
||||
* link it into the new equivalence class and flag it as
|
||||
* having been processed
|
||||
*/
|
||||
|
||||
bck[i] = newec;
|
||||
fwd[newec] = i;
|
||||
newec = i;
|
||||
cclflags[j] = 1; /* set flag so we don't reprocess */
|
||||
|
||||
/* get next equivalence class member */
|
||||
/* continue 2 */
|
||||
goto next_pt;
|
||||
}
|
||||
}
|
||||
|
||||
/* symbol isn't in character class. Put it in the old equivalence
|
||||
* class
|
||||
*/
|
||||
|
||||
bck[i] = oldec;
|
||||
|
||||
if ( oldec != NIL )
|
||||
fwd[oldec] = i;
|
||||
|
||||
oldec = i;
|
||||
next_pt:
|
||||
;
|
||||
}
|
||||
|
||||
if ( bck[cclm] != NIL || oldec != bck[cclm] )
|
||||
{
|
||||
bck[cclm] = NIL;
|
||||
fwd[oldec] = NIL;
|
||||
}
|
||||
|
||||
fwd[newec] = NIL;
|
||||
|
||||
/* find next ccl member to process */
|
||||
|
||||
for ( ++cclp; cclflags[cclp] && cclp < lenccl; ++cclp )
|
||||
{
|
||||
/* reset "doesn't need processing" flag */
|
||||
cclflags[cclp] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* mkechar - create equivalence class for single character
|
||||
*
|
||||
* synopsis
|
||||
* int tch, fwd[], bck[];
|
||||
* mkechar( tch, fwd, bck );
|
||||
*/
|
||||
|
||||
void mkechar(int tch, int fwd[], int bck[])
|
||||
{
|
||||
/* if until now the character has been a proper subset of
|
||||
* an equivalence class, break it away to create a new ec
|
||||
*/
|
||||
|
||||
if ( fwd[tch] != NIL )
|
||||
bck[fwd[tch]] = bck[tch];
|
||||
|
||||
if ( bck[tch] != NIL )
|
||||
fwd[bck[tch]] = fwd[tch];
|
||||
|
||||
fwd[tch] = NIL;
|
||||
bck[tch] = NIL;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user