Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • e3/wrappers/e3-require
  • waynelewis/e3-require
  • krisztianloki/e3-require
  • timokorhonen/e3-require
  • juntongliu/e3-require
  • roryclarke/e3-require
  • alfiorizzo/e3-require
  • lucasmagalhaes/e3-require
  • lucas-module-testgroup/e3-require
  • grzegorzkowalski/e3-require
  • anderslindh1/e3-require
11 results
Show changes
Showing
with 333 additions and 732 deletions
.PHONY: cellbuild .PHONY: cellbuild
## Builds the module while also searching in $(E3_CELL_PATH) for dependencies ## Builds the module while also searching in $(E3_CELL_PATH) for dependencies
cellbuild: build cellbuild: ${COMMON_DIR}/${METAFILE}
.PHONY: cellinstall .PHONY: cellinstall
## Installs the module in a local directory $(E3_CELL_PATH) ## Installs the module in a local directory $(E3_CELL_PATH)
cellinstall: install_module fix_permissions cellinstall: install fix_permissions
.PHONY: celluninstall .PHONY: celluninstall
## Remove the module from the local directory $(E3_CELL_PATH) ## Remove the module from the local directory $(E3_CELL_PATH)
......
# -*- mode: Makefile;-*- # -*- mode: Makefile;-*-
ifneq ($(E3_LOCAL_SOURCE),1) ifneq ($(E3_LOCAL_SOURCE),1)
.PHONY: devvars devenv devinit devbuild devclean devinstall devrebuild devuninstall devdistclean devconf devepics devepics-clean devepics-distclean devpatch devpatchrevert devexistent devdep devvers .PHONY: devvars devenv devinit devbuild devclean devinstall devrebuild devuninstall devdistclean devconf devepics devepics-clean devepics-distclean devpatch devexistent devdep devvers
devvars: vars devvars: vars
...@@ -30,7 +30,6 @@ devepics: nonexists ...@@ -30,7 +30,6 @@ devepics: nonexists
devepics-clean: nonexists devepics-clean: nonexists
devepics-distclean: nonexists devepics-distclean: nonexists
devpatch: nonexists devpatch: nonexists
devpatchrevert: nonexists
devexistent: nonexists devexistent: nonexists
devdep: nonexists devdep: nonexists
devvers: nonexists devvers: nonexists
...@@ -66,7 +65,6 @@ devepics: epics ...@@ -66,7 +65,6 @@ devepics: epics
devepics-clean: epics-clean devepics-clean: epics-clean
devepics-distclean: epics-distclean devepics-distclean: epics-distclean
devpatch: patch devpatch: patch
devpatchrevert: patchrevert
devexistent: existent devexistent: existent
devdep: dep devdep: dep
devvers: vers devvers: vers
......
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
.PHONY: help default install uninstall build rebuild clean conf all prebuild .PHONY: help default install uninstall build rebuild clean all prebuild
default: help default: help
# Include some checks before build happens
include $(E3_REQUIRE_CONFIG)/RULES_CHECKS
# # help is defined in # # help is defined in
# # https://gist.github.com/rcmachado/af3db315e31383502660 # # https://gist.github.com/rcmachado/af3db315e31383502660
help: help:
...@@ -28,9 +31,6 @@ help: ...@@ -28,9 +31,6 @@ help:
## Install module to $(E3_MODULES_INSTALL_LOCATION)
install: install_module hdrs
.PHONY: db .PHONY: db
db: err_no_db_rule db: err_no_db_rule
...@@ -38,48 +38,57 @@ db: err_no_db_rule ...@@ -38,48 +38,57 @@ db: err_no_db_rule
err_no_db_rule: err_no_db_rule:
$(error The 'db' target has been discontinued. If you have custom database expansion rule to use, please contact the e3 team) $(error The 'db' target has been discontinued. If you have custom database expansion rule to use, please contact the e3 team)
.PHONY: install_module # Decouple build and install targets by using metadata file generated during
install_module: build db_internal # build as install prerequisite.
# The metadata file target cannot depend on build, since its phony nature will
# trigger the rebuild anyway. Instead, the metadata file is created as a side
# effect of running the build target in separate make process.
${COMMON_DIR}/${METAFILE}:
$(QUIET) $(MAKE) build
## Install module to $(E3_MODULES_INSTALL_LOCATION)
install: ${COMMON_DIR}/${METAFILE}
$(QUIET) $(E3_MODULE_MAKE_CMDS) install $(QUIET) $(E3_MODULE_MAKE_CMDS) install
@echo "Installing metadata file $(MODULE_INSTALL_LOCATION)/${METAFILE}"
$(QUIET) install -m444 ${COMMON_DIR}/${METAFILE} ${MODULE_INSTALL_LOCATION}
.PHONY: check_uninstall .PHONY: check_uninstall
check_uninstall: check_uninstall:
## Uninstall the current module ## Uninstall the current module
uninstall: check_uninstall conf uninstall: check_uninstall
$(QUIET) $(E3_MODULE_MAKE_CMDS) uninstall $(QUIET) $(E3_MODULE_MAKE_CMDS) uninstall
## Build current module ## Build current module
build: conf checkout prebuild build: consistency_checks checkout prebuild db_internal
$(QUIET) $(E3_MODULE_MAKE_CMDS) build $(QUIET) $(E3_MODULE_MAKE_CMDS) build
@echo "Populating metadata file ${COMMON_DIR}/${METAFILE}"
@echo "wrapper_url: '$(${E3_MODULE_NAME}_E3_GIT_URL)'" > ${COMMON_DIR}/${METAFILE}
@echo "wrapper_git_desc: '$(${E3_MODULE_NAME}_E3_GIT_DESC)'" >> ${COMMON_DIR}/${METAFILE}
@echo "module_git_desc: '$(shell git rev-parse HEAD 2> /dev/null)'" >> ${COMMON_DIR}/${METAFILE}
## Run module-specific commands before building ## Run module-specific commands before building
prebuild: conf prebuild: consistency_checks
$(QUIET) $(E3_MODULE_MAKE_CMDS) prebuild $(QUIET) $(E3_MODULE_MAKE_CMDS) prebuild
## Displays information about the build process ## Displays information about the build process
debug: conf debug:
$(QUIET) $(E3_MODULE_MAKE_CMDS) debug $(QUIET) $(E3_MODULE_MAKE_CMDS) debug
.PHONY: db_internal .PHONY: db_internal
db_internal: conf db_internal: consistency_checks
$(QUIET) $(E3_MODULE_MAKE_CMDS) db_internal $(QUIET) $(E3_MODULE_MAKE_CMDS) db_internal
## Clean, build, and install the current module ## Clean, build, and install the current module
rebuild: clean build install rebuild: clean build install
## Deletes temporary build files ## Deletes temporary build files
clean: conf clean:
$(QUIET) $(E3_MODULE_MAKE_CMDS) clean $(QUIET) $(E3_MODULE_MAKE_CMDS) clean
## Initializes, patches, builds, and installs ## Initializes, patches, builds, and installs
all: init patch rebuild all: init patch rebuild
# Copy $(E3_MODULE_MAKEFILE) into $(E3_MODULE_SRC_PATH)
include $(REQUIRE_CONFIG)/RULES_CHECKS
conf: consistency_checks
$(QUIET) install -p -m 644 $(TOP)/$(E3_MODULE_MAKEFILE) $(E3_MODULE_SRC_PATH)/
.PHONY: init git-submodule-sync $(E3_MODULE_SRC_PATH) checkout .PHONY: init git-submodule-sync $(E3_MODULE_SRC_PATH) checkout
ifeq (,$(strip $(EPICS_MODULE_TAG))) ifeq (,$(strip $(EPICS_MODULE_TAG)))
......
# One should define the any dependency modules and EPICS base path
# in the following directory
.PHONY: epics-clean epics-distclean
epics-clean:
$(MAKE) -C $(E3_MODULE_SRC_PATH) clean
epics-distclean:
$(MAKE) -C $(E3_MODULE_SRC_PATH) distclean
.PHONY: patch patchrevert .PHONY: patch
## Apply Patch Files ## Apply Patch Files
patch: patch:
$(QUIET) $(call patch_site)
## Revert Patch Files define PATCH_TEMPLATE
patchrevert: patch: $1
$(QUIET) $(call patch_revert_site) .PHONY: $1
$1:
@echo "Applying patch $$@"
git apply --directory=$$(E3_MODULE_SRC_PATH) --ignore-whitespace -p0 $$@
endef
ifneq ($(strip $(PATCHES)),)
$(foreach patch,$(PATCHES),$(eval $(call PATCH_TEMPLATE,$(patch))))
else
patch:
@echo "No patches to apply"
endif
# -*- mode: Makefile;-*- # -*- mode: Makefile;-*-
include $(REQUIRE_CONFIG)/RULES_E3 include $(E3_REQUIRE_CONFIG)/RULES_E3
include $(REQUIRE_CONFIG)/RULES_CELL include $(E3_REQUIRE_CONFIG)/RULES_CELL
include $(REQUIRE_CONFIG)/DEFINES_FT include $(E3_REQUIRE_CONFIG)/DEFINES_FT
include $(REQUIRE_CONFIG)/RULES_PATCH include $(E3_REQUIRE_CONFIG)/RULES_PATCH
include $(REQUIRE_CONFIG)/RULES_TEST include $(E3_REQUIRE_CONFIG)/RULES_TEST
include $(REQUIRE_CONFIG)/RULES_DKMS include $(E3_REQUIRE_CONFIG)/RULES_DKMS
include $(REQUIRE_CONFIG)/RULES_VARS include $(E3_REQUIRE_CONFIG)/RULES_VARS
include $(REQUIRE_CONFIG)/RULES_DEV include $(E3_REQUIRE_CONFIG)/RULES_DEV
EPICS_BASE=/epics/base-7.0.6.1 EPICS_BASE=/epics/base-7.0.8.1
E3_REQUIRE_NAME:=require E3_REQUIRE_NAME:=require
E3_REQUIRE_VERSION:=4.0.0 E3_REQUIRE_VERSION:=5.1.1
# The definitions shown below can also be placed in an untracked RELEASE.local # The definitions shown below can also be placed in an untracked RELEASE.local
......
# -*- mode: Makefile;-*- # -*- mode: Makefile;-*-
# include $(EPICS_BASE)/configure/RULES
include $(REQUIRE_CONFIG)/DEFINES_FT
#
# We cannot use file operation in CentOS7.4,
# because Makefile version is 3.8.
include $(REQUIRE_CONFIG)/RULES_E3
include $(REQUIRE_CONFIG)/RULES_EPICS
include $(E3_REQUIRE_CONFIG)/RULES_E3
include $(TOP)/configure/module/RULES_REQUIRE include $(TOP)/configure/module/RULES_REQUIRE
include $(E3_REQUIRE_CONFIG)/DEFINES_FT
include $(REQUIRE_CONFIG)/RULES_PATCH include $(E3_REQUIRE_CONFIG)/RULES_PATCH
include $(REQUIRE_CONFIG)/RULES_VARS
include $(TOP)/configure/module/RULES_TEST include $(TOP)/configure/module/RULES_TEST
include $(E3_REQUIRE_CONFIG)/RULES_VARS
ifneq (,$(findstring dev,$(MAKECMDGOALS))) ifneq (,$(findstring dev,$(MAKECMDGOALS)))
include $(REQUIRE_CONFIG)/RULES_DEV include $(E3_REQUIRE_CONFIG)/RULES_DEV
endif endif
...@@ -8,7 +8,7 @@ FILE_FILTER:= %~ %\# ...@@ -8,7 +8,7 @@ FILE_FILTER:= %~ %\#
E3_TEST_SCRIPT := $(TOP)/tools/test_installed_modules.sh E3_TEST_SCRIPT := $(TOP)/tools/test_installed_modules.sh
# #
E3_SHELL_FILES := $(wildcard $(E3_MODULE_SRC_PATH)/tools/iocsh*) E3_SHELL_FILES := $(wildcard $(E3_MODULE_SRC_PATH)/tools/iocsh*)
E3_IOC_CFG_FILES += $(E3_MODULE_SRC_PATH)/tools/setE3Env.bash E3_IOC_CFG_FILES += $(E3_MODULE_SRC_PATH)/tools/activate
E3_IOC_CFG_FILES += $(E3_MODULE_SRC_PATH)/tools/promptE3Env.bash E3_IOC_CFG_FILES += $(E3_MODULE_SRC_PATH)/tools/promptE3Env.bash
E3_REQUIRE_CONF_FILES := $(filter-out $(FILE_FILTER), $(wildcard $(TOP)/configure/E3/*)) E3_REQUIRE_CONF_FILES := $(filter-out $(FILE_FILTER), $(wildcard $(TOP)/configure/E3/*))
...@@ -22,18 +22,17 @@ endif ...@@ -22,18 +22,17 @@ endif
install: requireconf install: requireconf
requireconf: e3-site-path e3-require-path requireconf: e3-site-path e3-require-path
$(QUIET) install -m 755 $(wildcard $(E3_MODULE_SRC_PATH)/tools/*.tcl) $(E3_REQUIRE_TOOLS)/
$(QUIET) install -m 644 $(E3_MODULE_SRC_PATH)/tools/driver.makefile $(E3_REQUIRE_TOOLS)/ $(QUIET) install -m 644 $(E3_MODULE_SRC_PATH)/tools/driver.makefile $(E3_REQUIRE_TOOLS)/
$(QUIET) install -m 755 $(E3_MODULE_SRC_PATH)/tools/*.sh $(E3_REQUIRE_TOOLS)/ $(QUIET) install -m 755 $(E3_MODULE_SRC_PATH)/tools/revision_number $(E3_REQUIRE_TOOLS)/
$(QUIET) install -m 755 $(E3_SHELL_FILES) $(E3_REQUIRE_BIN)/ $(QUIET) install -m 755 $(E3_SHELL_FILES) $(E3_REQUIRE_BIN)/
$(QUIET) install -m 644 $(E3_IOC_CFG_FILES) $(E3_REQUIRE_BIN)/ $(QUIET) install -m 644 $(E3_IOC_CFG_FILES) $(E3_REQUIRE_BIN)/
$(QUIET) install -m 644 $(E3_REQUIRE_CONF_FILES) $(E3_REQUIRE_CONFIG)/ $(QUIET) install -m 644 $(E3_REQUIRE_CONF_FILES) $(E3_REQUIRE_LOCATION)/configure/
e3-require-path: e3-require-path:
$(QUIET) install -d -m 755 $(E3_REQUIRE_TOOLS) $(QUIET) install -d -m 755 $(E3_REQUIRE_TOOLS)
$(QUIET) install -d -m 755 $(E3_REQUIRE_BIN) $(QUIET) install -d -m 755 $(E3_REQUIRE_BIN)
$(QUIET) install -d -m 755 $(E3_REQUIRE_CONFIG) $(QUIET) install -d -m 755 $(E3_REQUIRE_LOCATION)/configure
e3-site-path: e3-site-path:
...@@ -52,9 +51,6 @@ forceuninstall: conf ...@@ -52,9 +51,6 @@ forceuninstall: conf
consistency_checks: consistency_checks:
.PHONY: hdrs
hdrs:
VARS_EXCLUDES+=FILE_FILTER VARS_EXCLUDES+=FILE_FILTER
VARS_EXCLUDES+=E3_SHELL_FILES VARS_EXCLUDES+=E3_SHELL_FILES
VARS_EXCLUDES+=E3_IOC_CFG_FILES VARS_EXCLUDES+=E3_IOC_CFG_FILES
......
record (waveform, "$(REQUIRE_IOC):MODULES") record(waveform, "$(REQUIRE_IOC):Modules")
{ {
field (DESC, "List of loaded modules") field(DESC, "Names of loaded modules")
field (FTVL, "STRING") field(FTVL, "STRING")
field (NELM, "$(MODULE_COUNT)") field(NELM, "$(MODULE_COUNT)")
field (PINI, "YES") field(PINI, "YES")
field(DISP, "1")
info(Q:group, {
"$(REQUIRE_IOC):LoadedModules":{"value.MODS":{+trigger:"*",+channel:"VAL"}}
})
} }
record (waveform, "$(REQUIRE_IOC):VERSIONS") record (waveform, "$(REQUIRE_IOC):Versions")
{ {
field (DESC, "Versions of loaded modules") field (DESC, "Versions of loaded modules")
field (FTVL, "STRING") field (FTVL, "STRING")
field (NELM, "$(MODULE_COUNT)") field (NELM, "$(MODULE_COUNT)")
field (PINI, "YES") field (PINI, "YES")
info(Q:group, {
"$(REQUIRE_IOC):LoadedModules":{"value.VERS":{+type:"plain",+channel:"VAL"}}
})
} }
record (waveform, "$(REQUIRE_IOC):MOD_VER") record(waveform, "$(REQUIRE_IOC):ModuleVersions")
{ {
field (DESC, "List of loaded modules") field(DESC, "Name and version of the loaded modules")
field (FTVL, "CHAR") field(FTVL, "CHAR")
field (NELM, "$(BUFFER_SIZE)") field(NELM, "$(BUFFER_SIZE)")
field (PINI, "YES") field(PINI, "YES")
field(DISP, "1")
} }
record (stringin, "$(REQUIRE_IOC):$(MODULE)_VER") record(stringin, "$(REQUIRE_IOC):$(MODULE)Version")
{ {
field (DESC, "Module $(MODULE) version") field(DESC, "Module $(MODULE) version")
field (VAL, "$(VERSION)") field(VAL, "$(VERSION)")
field (PINI, "YES") field(PINI, "YES")
field(DISP, "1")
} }
record(stringin,"$(REQUIRE_IOC):BaseVersion") record(stringin,"$(REQUIRE_IOC):BaseVersion")
{ {
field (DESC,"EPICS Base Version") field(DESC, "EPICS Base version")
field (DTYP,"getenv") field(DTYP, "getenv")
field (INP,"@EPICS_VERSION_FULL") field(INP, "@EPICS_VERSION_FULL")
field (PINI,"YES") field(PINI, "YES")
field (DISP,1) field(DISP, "1")
}
# This record contains labels for the created NTTable, named $(REQUIRE_IOC):LoadedModules.
record(aai, "$(REQUIRE_IOC):Labels")
{
field(DESC, "Labels for the NTTable")
field(FTVL, "STRING")
field(NELM, "2")
field(INP, {const:["Module", "Version"]})
field(PINI, "YES")
field(DISP, "1")
info(Q:group, {
"$(REQUIRE_IOC):LoadedModules":{
+id:"epics:nt/NTTable:1.0",
"labels":{+type:"plain", +channel:"VAL"}
}
})
} }
/* Copyright (C) 2020 Dirk Zimoch */
/* Copyright (C) 2020-2023 European Spallation Source, ERIC */
#include <dbAccess.h>
#include <epicsExport.h>
#include <epicsStdio.h>
#include <epicsString.h>
#include <errlog.h>
#include <errno.h>
#include <initHooks.h>
#include <iocsh.h>
#include <stdlib.h>
#include <string.h>
struct cmditem {
struct cmditem *next;
char *cmd;
};
struct cmditem *cmdlist, **cmdlast = &cmdlist;
void afterInitHook(initHookState state) {
if (state != initHookAfterIocRunning) return;
struct cmditem *item = cmdlist;
struct cmditem *next = NULL;
while (item) {
printf("%s\n", item->cmd);
if (iocshCmd(item->cmd)) {
errlogPrintf("afterInit: Command '%s' failed to run\n", item->cmd);
};
next = item->next;
free(item->cmd);
free(item);
item = next;
}
}
static struct cmditem *newItem(char *cmd) {
struct cmditem *item;
item = malloc(sizeof(struct cmditem));
if (item == NULL) {
return NULL;
}
item->cmd = epicsStrDup(cmd);
item->next = NULL;
*cmdlast = item;
cmdlast = &item->next;
return item;
}
static const iocshFuncDef afterInitDef = {
"afterInit", 1,
(const iocshArg *[]){
&(iocshArg){"commandline", iocshArgString},
}};
static void afterInitFunc(const iocshArgBuf *args) {
static int first_time = 1;
char *cmd;
if (first_time) {
first_time = 0;
initHookRegister(afterInitHook);
}
if (interruptAccept) {
errlogPrintf("afterInit can only be used before iocInit\n");
return;
}
cmd = args[0].sval;
if (!cmd || !cmd[0]) {
errlogPrintf("Usage: afterInit \"command\"\n");
return;
}
struct cmditem *item = newItem(cmd);
if (!item)
errlogPrintf("afterInit: error adding command %s; %s", cmd,
strerror(errno));
}
static void afterInitRegister(void) {
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&afterInitDef, afterInitFunc);
}
}
epicsExportRegistrar(afterInitRegister);
registrar(afterInitRegister)
/* Copyright (C) 2020 Dirk Zimoch */
/* Copyright (C) 2020-2022 European Spallation Source, ERIC */
#include "asprintf.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/* some implementations have __va_copy instead of va_copy */
#if !defined(va_copy) && defined(__va_copy)
#define va_copy __va_copy
#endif
int vasprintf(char **pbuffer, const char *format, va_list ap) {
int len = -1;
#ifdef va_copy
va_list ap2;
va_copy(ap2, ap);
#else
/* if we have no va_copy, we probably don't need one */
#define ap2 ap
#endif // va_copy
#if defined(_WIN32)
len = _vscprintf(format, ap2);
#else
len = vsnprintf(NULL, 0, format, ap2);
#endif
#ifdef va_copy
va_end(ap2);
#endif // va_copy
if (len <= 0) {
fprintf(stderr, "vasprintf: error calculating needed size\n");
return -1;
}
*pbuffer = malloc(len + 1);
if (*pbuffer == NULL) return -1;
return vsprintf(*pbuffer, format, ap);
}
int asprintf(char **pbuffer, const char *format, ...) {
va_list ap;
int len;
va_start(ap, format);
len = vasprintf(pbuffer, format, ap);
va_end(ap);
return len;
}
/* Copyright (C) 2020 Dirk Zimoch */
/* Copyright (C) 2020-2022 European Spallation Source, ERIC */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <stdarg.h>
#ifndef __GNUC__
#define __attribute__(arg)
#endif // __GNUC__
int asprintf(char **pbuffer, const char *format, ...)
__attribute__((__format__(__printf__, 2, 3)));
int vasprintf(char **pbuffer, const char *format, va_list ap)
__attribute__((__format__(__printf__, 2, 0)));
#ifdef __cplusplus
}
#endif // __cplusplus
#include "common.h"
#include <dbAccess.h>
#include <errlog.h>
#include <errno.h>
#ifdef __MACH__
#include <mach/error.h>
#else
#include <error.h>
#endif
#include <limits.h>
#include <osiFileName.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *realpathSeparator(const char *location) {
size_t size = 0;
char *buffer = realpath(location, NULL);
if (!buffer) {
debug("require: realpath(%s) failed\n", location);
errlogPrintf("require: %s", strerror(errno));
return NULL;
}
size = strnlen(buffer, PATH_MAX);
/* linux realpath removes trailing slash */
if (buffer[size - 1] != OSI_PATH_SEPARATOR[0]) {
char *tmp = realloc(buffer, size + sizeof(OSI_PATH_SEPARATOR));
if (!tmp) {
free(buffer);
return NULL;
}
buffer = tmp;
strcpy(buffer + size, OSI_PATH_SEPARATOR);
}
return buffer;
}
int putenvprintf(const char *format, ...) {
va_list ap;
char *var = NULL;
char *val = NULL;
int status = 0;
if (!format) return -1;
va_start(ap, format);
if (vasprintf(&var, format, ap) < 0) {
errlogPrintf("require putenvprintf %s", strerror(errno));
return errno;
}
va_end(ap);
debug("require: putenv(\"%s\")\n", var);
val = strchr(var, '=');
if (!val) {
fprintf(stderr, "putenvprintf: string contains no =: %s\n", var);
status = -1;
} else {
*val++ = 0;
if (setenv(var, val, 1) != 0) {
errlogPrintf("require putenvprintf: setenv failed %s", strerror(errno));
status = errno;
}
}
free(var);
return status;
}
void pathAdd(const char *varname, const char *dirname) {
char *old_path = NULL;
if (!varname || !dirname) {
errlogPrintf("usage: pathAdd \"ENVIRONMENT_VARIABLE\",\"directory\"\n");
errlogPrintf(
" Adds or moves the directory to the front of the "
"ENVIRONMENT_VARIABLE\n");
errlogPrintf(" but after a leading \".\".\n");
return;
}
/* add directory to front */
old_path = getenv(varname);
if (old_path == NULL) {
putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s", varname, dirname);
} else {
size_t len = strnlen(dirname, PATH_MAX);
char *p = NULL;
/* skip over "." at the beginning */
if (old_path[0] == '.' && old_path[1] == OSI_PATH_LIST_SEPARATOR[0])
old_path += 2;
/* If directory is already in path, move it to front */
p = old_path;
while ((p = strstr(p, dirname)) != NULL) {
if ((p == old_path || *(p - 1) == OSI_PATH_LIST_SEPARATOR[0]) &&
(p[len] == 0 || p[len] == OSI_PATH_LIST_SEPARATOR[0])) {
if (p == old_path) break; /* already at front, nothing to do */
memmove(old_path + len + 1, old_path, p - old_path - 1);
strcpy(old_path, dirname);
old_path[len] = OSI_PATH_LIST_SEPARATOR[0];
debug("require: modified %s=%s\n", varname, old_path);
break;
}
p += len;
}
if (p == NULL) /* add new directory to the front (after "." )*/
putenvprintf("%s=." OSI_PATH_LIST_SEPARATOR "%s" OSI_PATH_LIST_SEPARATOR
"%s",
varname, dirname, old_path);
}
}
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
extern int requireDebug;
#define debug(...) \
if (requireDebug) printf(__VA_ARGS__)
char *realpathSeparator(const char *location);
int putenvprintf(const char *format, ...);
void pathAdd(const char *varname, const char *dirname);
#endif /*__COMMON_H_*/
registrar(dbLoadTemplateRegister)
/*************************************************************************\
* 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.
\*************************************************************************/
#pragma once
#include "dbCoreAPI.h"
DBCORE_API int dbLoadTemplate(const char *sub_file, const char *cmd_collect,
const char *path);
%{
/*************************************************************************\
* Copyright (c) 2006 UChicago, 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.
\*************************************************************************/
/* for vasprintf */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#if !defined (_WIN32)
#include <unistd.h>
#endif
#include "macLib.h"
#include "dbmf.h"
#include "dbAccess.h"
#include "dbLoadTemplate.h"
#include "osiFileName.h"
#include "epicsVersion.h"
#if defined(vxWorks) || defined (_WIN32)
#include "asprintf.h"
#endif
#include "iocsh.h"
#include "epicsExport.h"
#if (EPICS_VERSION*10000+EPICS_REVISION*100+EPICS_MODIFICATION<31412)
#define dbmfStrdup(s) strcpy(dbmfMalloc(strlen((char*)(s))+1),(char*)(s))
#endif
#if (EPICS_VERSION*10000+EPICS_REVISION*100+EPICS_MODIFICATION>=31600)
#define dbmfStrdup(s) dbmfStrdup((char*)s)
#endif
static int line_num;
static int yyerror(char* str);
static char *sub_collect = NULL;
static char *sub_locals;
static char **vars = NULL;
static char *db_file_name = NULL;
static int var_count, sub_count;
/* We allocate MAX_VAR_FACTOR chars in the sub_collect string for each
* "variable=value," segment, and will accept at most dbTemplateMaxVars
* template variables. The user can adjust that variable to increase
* the number of variables or the length allocated for the buffer.
*/
#define MAX_VAR_FACTOR 50
int dbTemplateMaxVars = 100;
%}
%start substitution_file
%token <Str> WORD QUOTE
%token DBFILE
%token PATTERN
%token GLOBAL
%token EQUALS COMMA
%left O_PAREN C_PAREN
%left O_BRACE C_BRACE
%union
{
int Int;
char Char;
char *Str;
double Real;
}
%%
substitution_file: global_or_template
| substitution_file global_or_template
;
global_or_template: global_definitions
| template_substitutions
;
global_definitions: GLOBAL O_BRACE C_BRACE
| GLOBAL O_BRACE variable_definitions C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "global_definitions: %s\n", sub_collect+1);
#endif
sub_locals += strlen(sub_locals);
}
;
template_substitutions: template_filename O_BRACE C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "template_substitutions: %s unused\n", db_file_name);
#endif
dbmfFree(db_file_name);
db_file_name = NULL;
}
| template_filename O_BRACE substitutions C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "template_substitutions: %s finished\n", db_file_name);
#endif
dbmfFree(db_file_name);
db_file_name = NULL;
}
;
template_filename: DBFILE WORD
{
#ifdef ERROR_STUFF
fprintf(stderr, "template_filename: %s\n", $2);
#endif
var_count = 0;
db_file_name = dbmfMalloc(strlen($2)+1);
strcpy(db_file_name, $2);
dbmfFree($2);
}
| DBFILE QUOTE
{
#ifdef ERROR_STUFF
fprintf(stderr, "template_filename: \"%s\"\n", $2);
#endif
var_count = 0;
db_file_name = dbmfMalloc(strlen($2)+1);
strcpy(db_file_name, $2);
dbmfFree($2);
}
;
substitutions: pattern_substitutions
| variable_substitutions
;
pattern_substitutions: PATTERN O_BRACE C_BRACE
| PATTERN O_BRACE C_BRACE pattern_definitions
| PATTERN O_BRACE pattern_names C_BRACE
| PATTERN O_BRACE pattern_names C_BRACE pattern_definitions
;
pattern_names: pattern_name
| pattern_names COMMA
| pattern_names pattern_name
;
pattern_name: WORD
{
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_name: [%d] = %s\n", var_count, $1);
#endif
if (var_count >= dbTemplateMaxVars) {
fprintf(stderr,
"More than dbTemplateMaxVars = %d macro variables used\n",
dbTemplateMaxVars);
yyerror(NULL);
}
else {
vars[var_count] = dbmfMalloc(strlen($1)+1);
strcpy(vars[var_count], $1);
var_count++;
dbmfFree($1);
}
}
;
pattern_definitions: pattern_definition
| pattern_definitions pattern_definition
;
pattern_definition: global_definitions
| O_BRACE C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_definition: pattern_values empty\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
}
| O_BRACE pattern_values C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_definition:\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
*sub_locals = '\0';
sub_count = 0;
}
| WORD O_BRACE pattern_values C_BRACE
{ /* DEPRECATED SYNTAX */
fprintf(stderr,
"dbLoadTemplate: Substitution file uses deprecated syntax.\n"
" the string '%s' on line %d that comes just before the\n"
" '{' character is extraneous and should be removed.\n",
$1, line_num);
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_definition:\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
dbmfFree($1);
*sub_locals = '\0';
sub_count = 0;
}
;
pattern_values: pattern_value
| pattern_values COMMA
| pattern_values pattern_value
;
pattern_value: QUOTE
{
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_value: [%d] = \"%s\"\n", sub_count, $1);
#endif
if (sub_count < var_count) {
strcat(sub_locals, ",");
strcat(sub_locals, vars[sub_count]);
strcat(sub_locals, "=\"");
strcat(sub_locals, $1);
strcat(sub_locals, "\"");
sub_count++;
} else {
fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
line_num);
}
dbmfFree($1);
}
| WORD
{
#ifdef ERROR_STUFF
fprintf(stderr, "pattern_value: [%d] = %s\n", sub_count, $1);
#endif
if (sub_count < var_count) {
strcat(sub_locals, ",");
strcat(sub_locals, vars[sub_count]);
strcat(sub_locals, "=");
strcat(sub_locals, $1);
sub_count++;
} else {
fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
line_num);
}
dbmfFree($1);
}
;
variable_substitutions: variable_substitution
| variable_substitutions variable_substitution
;
variable_substitution: global_definitions
| O_BRACE C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "variable_substitution: variable_definitions empty\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
}
| O_BRACE variable_definitions C_BRACE
{
#ifdef ERROR_STUFF
fprintf(stderr, "variable_substitution:\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
*sub_locals = '\0';
}
| WORD O_BRACE variable_definitions C_BRACE
{ /* DEPRECATED SYNTAX */
fprintf(stderr,
"dbLoadTemplate: Substitution file uses deprecated syntax.\n"
" the string '%s' on line %d that comes just before the\n"
" '{' character is extraneous and should be removed.\n",
$1, line_num);
#ifdef ERROR_STUFF
fprintf(stderr, "variable_substitution:\n");
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
#endif
dbLoadRecords(db_file_name, sub_collect+1);
dbmfFree($1);
*sub_locals = '\0';
}
;
variable_definitions: variable_definition
| variable_definitions COMMA
| variable_definitions variable_definition
;
variable_definition: WORD EQUALS WORD
{
#ifdef ERROR_STUFF
fprintf(stderr, "variable_definition: %s = %s\n", $1, $3);
#endif
strcat(sub_locals, ",");
strcat(sub_locals, $1);
strcat(sub_locals, "=");
strcat(sub_locals, $3);
dbmfFree($1); dbmfFree($3);
}
| WORD EQUALS QUOTE
{
#ifdef ERROR_STUFF
fprintf(stderr, "variable_definition: %s = \"%s\"\n", $1, $3);
#endif
strcat(sub_locals, ",");
strcat(sub_locals, $1);
strcat(sub_locals, "=\"");
strcat(sub_locals, $3);
strcat(sub_locals, "\"");
dbmfFree($1); dbmfFree($3);
}
| QUOTE EQUALS QUOTE
{
#ifdef ERROR_STUFF
fprintf(stderr, "variable_definition: \"%s\" = \"%s\"\n", $1, $3);
#endif
strcat(sub_locals, ",\"");
strcat(sub_locals, $1);
strcat(sub_locals, "\"=\"");
strcat(sub_locals, $3);
strcat(sub_locals, "\"");
dbmfFree($1); dbmfFree($3);
}
;
%%
#include "dbLoadTemplate_lex.c"
static int yyerror(char* str)
{
if (str)
fprintf(stderr, "Substitution file error: %s\n", str);
else
fprintf(stderr, "Substitution file error.\n");
fprintf(stderr, "line %d: '%s'\n", line_num, yytext);
return 0;
}
static int is_not_inited = 1;
int dbLoadTemplate(const char *sub_file, const char *cmd_collect, const char *path)
{
FILE *fp;
int i;
line_num = 1;
if (!sub_file || !*sub_file) {
fprintf(stderr, "must specify variable substitution file\n");
return -1;
}
if (dbTemplateMaxVars < 1) {
fprintf(stderr,"Error: dbTemplateMaxVars = %d, must be positive\n",
dbTemplateMaxVars);
return -1;
}
fp = fopen(sub_file, "r");
if (!fp && sub_file[0] != OSI_PATH_SEPARATOR[0]) {
const char *dirname, *end;
int dirlen;
char* filename;
if (!path || !*path) {
path = getenv("EPICS_DB_INCLUDE_PATH");
}
for(dirname = path; dirname != NULL; dirname = end) {
end = strchr(dirname, OSI_PATH_LIST_SEPARATOR[0]);
if (end) dirlen = (int)(end++ - dirname);
else dirlen = (int)strlen(dirname);
if (dirlen == 0) continue; /* ignore empty path elements */
if (dirlen == 1 && dirname[0] == '.') continue; /* we had . already */
filename = NULL;
if (asprintf(&filename, "%.*s" OSI_PATH_SEPARATOR "%s", dirlen, dirname, sub_file) < 0)
{
fprintf(stderr,"dbLoadTemplate: out of memory\n");
break;
}
fp = fopen(filename, "r");
free(filename);
if (fp) break;
}
}
if (!fp) {
fprintf(stderr, "dbLoadTemplate: error opening sub file %s: %s\n", sub_file, strerror(errno));
return -1;
}
vars = malloc(dbTemplateMaxVars * sizeof(char*));
sub_collect = malloc(dbTemplateMaxVars * MAX_VAR_FACTOR);
if (!vars || !sub_collect) {
free(vars);
free(sub_collect);
fclose(fp);
fprintf(stderr, "dbLoadTemplate: Out of memory!\n");
return -1;
}
strcpy(sub_collect, ",");
if (cmd_collect && *cmd_collect) {
strcat(sub_collect, cmd_collect);
sub_locals = sub_collect + strlen(sub_collect);
} else {
sub_locals = sub_collect;
*sub_locals = '\0';
}
var_count = 0;
sub_count = 0;
if (is_not_inited) {
yyin = fp;
is_not_inited = 0;
} else {
yyrestart(fp);
}
yyparse();
for (i = 0; i < var_count; i++) {
dbmfFree(vars[i]);
}
free(vars);
free(sub_collect);
vars = NULL;
fclose(fp);
if (db_file_name) {
dbmfFree(db_file_name);
db_file_name = NULL;
}
return 0;
}
#include "registry.h"
epicsExportAddress(int, dbTemplateMaxVars);
static const iocshFuncDef dbLoadTemplateDef = {
"dbLoadTemplate", 3, (const iocshArg *[]) {
&(iocshArg) { "filename", iocshArgString },
&(iocshArg) { "\"macro=value,...\"", iocshArgString },
&(iocshArg) { "searchpath", iocshArgString },
}};
#ifdef __GNUC__
/* Without this I always get the original dbLoadTemplate linked instead of my version */
int __dbLoadTemplate(const char *sub_file, const char *cmd_collect, const char *path) __attribute__ ((alias ("dbLoadTemplate")));
#define dbLoadTemplate __dbLoadTemplate
#endif
static void dbLoadTemplateFunc(const iocshArgBuf *args)
{
dbLoadTemplate(args[0].sval, args[1].sval, args[2].sval);
}
typedef struct iocshCommand {
iocshFuncDef const *pFuncDef;
iocshCallFunc func;
struct iocshCommand *next;
}iocshCommand;
static void dbLoadTemplateRegister(void)
{
static int firstTime = 1;
if (firstTime) {
iocshRegister(&dbLoadTemplateDef, dbLoadTemplateFunc);
firstTime = 0;
}
}
epicsExportRegistrar(dbLoadTemplateRegister);
/*************************************************************************\
* Copyright (c) 2006 UChicago, 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.
\*************************************************************************/
newline "\n"
backslash "\\"
doublequote "\""
singlequote "'"
comment "#"
whitespace [ \t\r]
escape {backslash}.
dstringchar [^"\n\\]
sstringchar [^'\n\\]
/*
This breaks backward compatibility to 3.14.8:
bareword [a-zA-Z0-9_\-+:./\\\[\]<>;]
Re-enable unquoted chars except #
*/
bareword [a-zA-Z0-9_\-+:./\\\[\]<>;^~*%!|&$()@?]
%%
"pattern" { return(PATTERN); }
"file" { return(DBFILE); }
"global" { return(GLOBAL); }
{doublequote}({dstringchar}|{escape})*{doublequote} |
{singlequote}({sstringchar}|{escape})*{singlequote} {
yylval.Str = dbmfStrdup(yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(QUOTE);
}
{bareword}+ {
yylval.Str = dbmfStrdup(yytext);
return(WORD);
}
"=" { return(EQUALS); }
"," { return(COMMA); }
"{" { return(O_BRACE); }
"}" { return(C_BRACE); }
{comment}.* ;
{whitespace} ;
{newline} { line_num++; }
. {
char message[40];
sprintf(message, "invalid character '%c'", yytext[0]);
yyerror(message);
/* Suppress compiler warning messages */
if (0) yyunput('c',NULL);
if (0) yy_switch_to_buffer(NULL);
}
%%