Merge branch 'libcom/master' back

This commit is contained in:
Ralph Lange
2018-06-19 16:52:24 +02:00
605 changed files with 111933 additions and 0 deletions

View 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

View 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

View 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
View 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

View 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

View 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;
}

View 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;
}

View 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);

View 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>

View 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);
}

View 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 */
};

View 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;
}

View 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

View 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

View 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))

View 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

View 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

View 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

View 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

View File

@@ -0,0 +1,6 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile

View File

@@ -0,0 +1,2 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS

View File

@@ -0,0 +1,2 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP

36
modules/libcom/src/Com.rc Normal file
View 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

View 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) $< $@

View 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

View 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

View 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*/

View 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);
}

File diff suppressed because it is too large Load Diff

View 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);
}
%%

View 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);
}

View 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*/

View 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

View 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;
}

View 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*/

View 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

View 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;
}

View 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++;
}
}
}

View 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 */

View 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 */

View 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

View 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__

View 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__

View 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

View 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);
}

View 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*/

View 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

View 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>.

View 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

View 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

View 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;
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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

View 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));
}

View 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 */

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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

View 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)

View 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*/

View 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*/

View 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);
}
}

View 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 */

View 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);
}

View 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*/

View 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 $_;
}

View 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

View 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 &reg)
{
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 &regIn)
{
fdReg *pItemFound;
pItemFound = this->fdTbl.remove (regIn);
if (pItemFound!=&regIn) {
fprintf(stderr,
"fdManager::removeReg() bad fd registration object\n");
return;
}
//
// signal fdManager that the fdReg was deleted
// during the call back
//
if (this->pCBReg == &regIn) {
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>;

View 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 &reg);
void removeReg (fdReg &reg);
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

View 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);
}

View 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) */

View 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.

View 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.

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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)

View 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 );
}

File diff suppressed because it is too large Load Diff

View 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