update softMain.cpp from Base circa 7.0.4
This commit is contained in:
@ -7,242 +7,246 @@
|
||||
* found in the file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* Copyed from EPICS Base 3.16 branch */
|
||||
/* Author: Andrew Johnson Date: 2003-04-08 */
|
||||
|
||||
/* Author: Andrew Johnson Date: 2003-04-08 */
|
||||
|
||||
/* Usage:
|
||||
* softIoc [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]
|
||||
* [-m macro=value,macro2=value2] [-d file.db]
|
||||
* [-x prefix] [st.cmd]
|
||||
*
|
||||
* If used the -D option must come first, and specify the
|
||||
* path to the softIoc.dbd file. The compile-time install
|
||||
* location is saved in the binary as a default.
|
||||
*
|
||||
* Usage information will be printed if -h is given, then
|
||||
* the program will exit normally.
|
||||
*
|
||||
* The -S option prevents an interactive shell being started
|
||||
* after all arguments have been processed.
|
||||
*
|
||||
* Previous versions accepted a -s option to cause a shell
|
||||
* to be started; this option is still accepted but ignored
|
||||
* since a command shell is now started by default.
|
||||
*
|
||||
* Access Security can be enabled with the -a option giving
|
||||
* the name of the configuration file; if any macros were
|
||||
* set with -m before the -a option was given, they will be
|
||||
* used as access security substitution macros.
|
||||
*
|
||||
* Any number of -m and -d arguments can be interspersed;
|
||||
* the macros are applied to the following .db files. Each
|
||||
* later -m option causes earlier macros to be discarded.
|
||||
*
|
||||
* The -x option loads the softIocExit.db with the macro
|
||||
* IOC set to the string provided. This database contains
|
||||
* a subroutine record named $(IOC):exit which has its field
|
||||
* SNAM set to "exit". When this record is processed, the
|
||||
* subroutine that runs will call epicsExit() with the value
|
||||
* of the field A determining whether the exit status is
|
||||
* EXIT_SUCCESS if (A == 0.0) or EXIT_FAILURE (A != 0.0).
|
||||
*
|
||||
* A st.cmd file is optional. If any databases were loaded
|
||||
* the st.cmd file will be run *after* iocInit. To perform
|
||||
* iocsh commands before iocInit, all database loading must
|
||||
* be performed by the script itself, or by the user from
|
||||
* the interactive IOC shell.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <epicsGetopt.h>
|
||||
#include "registryFunction.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "subRecord.h"
|
||||
#include "dbAccess.h"
|
||||
#include "asDbLib.h"
|
||||
#include "iocInit.h"
|
||||
#include "iocsh.h"
|
||||
#include "osiFileName.h"
|
||||
#include "epicsInstallDir.h"
|
||||
|
||||
extern "C" int softIocPVA_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
|
||||
#ifdef __rtems__
|
||||
#define DBD_FILE "dbd/softIocPVA.dbd"
|
||||
#define EXIT_FILE "db/softIocExit.db"
|
||||
#else
|
||||
#define DBD_FILE FINAL_LOCATION "/dbd/softIocPVA.dbd"
|
||||
#define EXIT_FILE FINAL_LOCATION "/db/softIocExit.db"
|
||||
#ifndef EPICS_BASE
|
||||
// so IDEs knows EPICS_BASE is a string constant
|
||||
# define EPICS_BASE "/"
|
||||
# error -DEPICS_BASE required
|
||||
#endif
|
||||
|
||||
#ifdef VERSION_INT
|
||||
#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
|
||||
#define USE_EXIT_LATER
|
||||
#endif
|
||||
#endif
|
||||
const char *arg0;
|
||||
const char *base_dbd = DBD_FILE;
|
||||
const char *exit_db = EXIT_FILE;
|
||||
#define DBD_BASE "dbd" OSI_PATH_SEPARATOR "softIoc.dbd"
|
||||
#define EXIT_BASE "db" OSI_PATH_SEPARATOR "softIocExit.db"
|
||||
#define DBD_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR DBD_BASE
|
||||
#define EXIT_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR EXIT_BASE
|
||||
#define DBD_FILE EPICS_BASE OSI_PATH_SEPARATOR DBD_BASE
|
||||
#define EXIT_FILE EPICS_BASE OSI_PATH_SEPARATOR EXIT_BASE
|
||||
|
||||
namespace {
|
||||
|
||||
static void exitSubroutine(subRecord *precord) {
|
||||
#ifdef USE_EXIT_LATER
|
||||
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
#else
|
||||
epicsExit((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void usage(int status) {
|
||||
printf("Usage: %s [-D softIoc.dbd] [-h] [-S] [-a ascf]\n", arg0);
|
||||
puts("\t[-m macro=value,macro2=value2] [-d file.db]");
|
||||
puts("\t[-x prefix] [st.cmd]");
|
||||
puts("Compiled-in path to softIocPVA.dbd is:");
|
||||
printf("\t%s\n", base_dbd);
|
||||
epicsExit(status);
|
||||
void usage(const char *arg0, const std::string& base_dbd) {
|
||||
std::cout<<"Usage: "<<arg0<<
|
||||
" [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]\n"
|
||||
"[-m macro=value,macro2=value2] [-d file.db]\n"
|
||||
"[-x prefix] [st.cmd]\n"
|
||||
"\n"
|
||||
" -D <dbd> If used, must come first. Specify the path to the softIoc.dbdfile."
|
||||
" The compile-time install location is saved in the binary as a default.\n"
|
||||
"\n"
|
||||
" -h Print this mesage and exit.\n"
|
||||
"\n"
|
||||
" -S Prevents an interactive shell being started.\n"
|
||||
"\n"
|
||||
" -s Previously caused a shell to be started. Now accepted and ignored.\n"
|
||||
"\n"
|
||||
" -a <acf> Access Security configuration file. Macro substitution is\n"
|
||||
" performed.\n"
|
||||
"\n"
|
||||
" -m <MAC>=<value>,... Set/replace macro definitions used by subsequent -d and\n"
|
||||
" -a.\n"
|
||||
"\n"
|
||||
" -d <db> Load records from file (dbLoadRecords). Macro substitution is\n"
|
||||
" performed.\n"
|
||||
"\n"
|
||||
" -x <prefix> Load softIocExit.db. Provides a record \"<prefix>:exit\".\n"
|
||||
" Put 0 to exit with success, or non-zero to exit with an error.\n"
|
||||
"\n"
|
||||
"Any number of -m and -d arguments can be interspersed; the macros are applied\n"
|
||||
"to the following .db files. Each later -m option causes earlier macros to be\n"
|
||||
"discarded.\n"
|
||||
"\n"
|
||||
"A st.cmd file is optional. If any databases were loaded the st.cmd file will\n"
|
||||
"be run *after* iocInit. To perform iocsh commands before iocInit, all database\n"
|
||||
"loading must be performed by the script itself, or by the user from the\n"
|
||||
"interactive IOC shell.\n"
|
||||
"\n"
|
||||
"Compiled-in path to softIoc.dbd is:\n"
|
||||
"\t"<<base_dbd.c_str()<<"\n";
|
||||
}
|
||||
|
||||
void errIf(int ret, const std::string& msg)
|
||||
{
|
||||
if(ret)
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
bool lazy_dbd_loaded;
|
||||
|
||||
void lazy_dbd(const std::string& dbd_file) {
|
||||
if(lazy_dbd_loaded) return;
|
||||
lazy_dbd_loaded = true;
|
||||
|
||||
errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
|
||||
std::string("Failed to load DBD file: ")+dbd_file);
|
||||
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
|
||||
|
||||
softIoc_registerRecordDeviceDriver(pdbbase);
|
||||
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *dbd_file = const_cast<char*>(base_dbd);
|
||||
char *macros = NULL;
|
||||
char xmacro[PVNAME_STRINGSZ + 4];
|
||||
int startIocsh = 1; /* default = start shell */
|
||||
int loadedDb = 0;
|
||||
|
||||
arg0 = strrchr(*argv, '/');
|
||||
if (!arg0) {
|
||||
arg0 = *argv;
|
||||
} else {
|
||||
++arg0; /* skip the '/' */
|
||||
}
|
||||
|
||||
--argc, ++argv;
|
||||
|
||||
/* Do this here in case the dbd file not available */
|
||||
if (argc>0 && **argv=='-' && (*argv)[1]=='h') {
|
||||
usage(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (argc>1 && **argv=='-' && (*argv)[1]=='D') {
|
||||
dbd_file = *++argv;
|
||||
argc -= 2;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (dbLoadDatabase(dbd_file, NULL, NULL)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
softIocPVA_registerRecordDeviceDriver(pdbbase);
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
try {
|
||||
std::string dbd_file(DBD_FILE),
|
||||
exit_file(EXIT_FILE),
|
||||
macros, // scratch space for macros (may be given more than once)
|
||||
xmacro;
|
||||
bool interactive = true;
|
||||
bool loadedDb = false;
|
||||
|
||||
while (argc>1 && **argv == '-') {
|
||||
switch ((*argv)[1]) {
|
||||
case 'a':
|
||||
if (macros) asSetSubstitutions(macros);
|
||||
asSetFilename(*++argv);
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (dbLoadRecords(*++argv, macros)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
loadedDb = 1;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
|
||||
case 'm':
|
||||
macros = *++argv;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
startIocsh = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
epicsSnprintf(xmacro, sizeof xmacro, "IOC=%s", *++argv);
|
||||
if (dbLoadRecords(exit_db, xmacro)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
loadedDb = 1;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: option '%s' not recognized\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
// attempt to compute relative paths
|
||||
{
|
||||
std::string prefix;
|
||||
char *cprefix = epicsGetExecDir();
|
||||
if(cprefix) {
|
||||
try {
|
||||
prefix = cprefix;
|
||||
free(cprefix);
|
||||
} catch(...) {
|
||||
free(cprefix);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
dbd_file = prefix + DBD_FILE_REL;
|
||||
exit_file = prefix + EXIT_FILE_REL;
|
||||
}
|
||||
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage(argv[0], dbd_file);
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0], dbd_file);
|
||||
std::cerr<<"Unknown argument: -"<<char(opt)<<"\n";
|
||||
epicsExit(2);
|
||||
return 2;
|
||||
case 'a':
|
||||
lazy_dbd(dbd_file);
|
||||
if (!macros.empty()) {
|
||||
if(asSetSubstitutions(macros.c_str()))
|
||||
throw std::bad_alloc();
|
||||
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
|
||||
}
|
||||
if(asSetFilename(optarg))
|
||||
throw std::bad_alloc();
|
||||
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
|
||||
break;
|
||||
case 'D':
|
||||
if(lazy_dbd_loaded) {
|
||||
throw std::runtime_error("-D specified too late. softIoc.dbd already loaded.\n");
|
||||
}
|
||||
dbd_file = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
lazy_dbd(dbd_file);
|
||||
errIf(dbLoadRecords(optarg, macros.c_str()),
|
||||
std::string("Failed to load: ")+optarg);
|
||||
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
|
||||
if(!macros.empty())
|
||||
std::cout<<", \""<<macros<<"\"";
|
||||
std::cout<<")\n";
|
||||
loadedDb = true;
|
||||
break;
|
||||
case 'm':
|
||||
macros = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
interactive = false;
|
||||
break;
|
||||
case 's':
|
||||
break; // historical
|
||||
case 'x':
|
||||
lazy_dbd(dbd_file);
|
||||
xmacro = "IOC=";
|
||||
xmacro += optarg;
|
||||
errIf(dbLoadRecords(exit_file.c_str(), xmacro.c_str()),
|
||||
std::string("Failed to load: ")+exit_file);
|
||||
loadedDb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lazy_dbd(dbd_file);
|
||||
|
||||
if(optind<argc) {
|
||||
// run script
|
||||
// ignore any extra positional args (historical)
|
||||
|
||||
std::cout<<"# Begin "<<argv[optind]<<"\n";
|
||||
errIf(iocsh(argv[optind]),
|
||||
std::string("Error in ")+argv[optind]);
|
||||
std::cout<<"# End "<<argv[optind]<<"\n";
|
||||
|
||||
epicsThreadSleep(0.2);
|
||||
loadedDb = true; /* Give it the benefit of the doubt... */
|
||||
}
|
||||
|
||||
if (loadedDb) {
|
||||
std::cout<<"iocInit()\n";
|
||||
iocInit();
|
||||
epicsThreadSleep(0.2);
|
||||
}
|
||||
|
||||
if(interactive) {
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
if(iocsh(NULL)) {
|
||||
epicsExit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (loadedDb) {
|
||||
epicsThreadExitMain();
|
||||
|
||||
} else {
|
||||
usage(argv[0], dbd_file);
|
||||
std::cerr<<"Nothing to do!\n";
|
||||
epicsExit(1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
|
||||
}catch(std::exception& e){
|
||||
std::cerr<<"Error: "<<e.what()<<"\n";
|
||||
epicsExit(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (argc>0 && **argv=='-') {
|
||||
switch((*argv)[1]) {
|
||||
case 'a':
|
||||
case 'd':
|
||||
case 'm':
|
||||
case 'x':
|
||||
printf("%s: missing argument to option '%s'\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
|
||||
case 'S':
|
||||
startIocsh = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: option '%s' not recognized\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (loadedDb) {
|
||||
iocInit();
|
||||
epicsThreadSleep(0.2);
|
||||
}
|
||||
|
||||
/* run user's startup script */
|
||||
if (argc>0) {
|
||||
if (iocsh(*argv)) epicsExit(EXIT_FAILURE);
|
||||
epicsThreadSleep(0.2);
|
||||
loadedDb = 1; /* Give it the benefit of the doubt... */
|
||||
}
|
||||
|
||||
/* start an interactive shell if it was requested */
|
||||
if (startIocsh) {
|
||||
iocsh(NULL);
|
||||
} else {
|
||||
if (loadedDb) {
|
||||
epicsThreadExitMain();
|
||||
} else {
|
||||
printf("%s: Nothing to do!\n", arg0);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
epicsExit(EXIT_SUCCESS);
|
||||
/*Note that the following statement will never be executed*/
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user