From ea1b208c33295f0b81f369bcb638a73c5a83c439 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 24 Jun 2019 13:23:28 -0700 Subject: [PATCH] redo softIoc to be more c++y --- modules/database/src/std/softIoc/softMain.cpp | 419 ++++++++---------- 1 file changed, 197 insertions(+), 222 deletions(-) diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index 01ef19b2f..bc945c80e 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -9,55 +9,12 @@ /* 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 -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "registryFunction.h" #include "epicsThread.h" #include "epicsExit.h" @@ -74,6 +31,12 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); +#ifndef EPICS_BASE +// so IDEs knows EPICS_BASE is a string constant +# define EPICS_BASE "/" +# error -DEPICS_BASE required +#endif + #define DBD_BASE "dbd/softIoc.dbd" #define EXIT_BASE "db/softIocExit.db" #define DBD_FILE_REL "../../" DBD_BASE @@ -81,190 +44,202 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); #define DBD_FILE EPICS_BASE "/" DBD_BASE #define EXIT_FILE EPICS_BASE "/" EXIT_BASE -const char *arg0; -const char *base_dbd = DBD_FILE; -const char *exit_db = EXIT_FILE; - -static void preparePath(void) -{ - FILE *fp; - char *prefix = epicsGetExecDir(); - char *dbd, *exit; - if(!prefix) return; - - dbd = (char*)malloc(strlen(prefix) + strlen(DBD_FILE_REL) + 1); - if(dbd) { - dbd[0] = '\0'; - strcat(dbd, prefix); - strcat(dbd, DBD_FILE_REL); - printf("Testing '%s'\n", dbd); - if((fp = fopen(dbd, "rb"))!=NULL) { - fclose(fp); - base_dbd = dbd; - } - } - - exit = (char*)malloc(strlen(prefix) + strlen(EXIT_FILE_REL) + 1); - if(exit) { - exit[0] = '\0'; - strcat(exit, prefix); - strcat(exit, EXIT_FILE_REL); - if((fp = fopen(exit, "rb"))!=NULL) { - fclose(fp); - exit_db = exit; - } - } -} +namespace { static void exitSubroutine(subRecord *precord) { epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE); } -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 softIoc.dbd is:"); - printf("\t%s\n", base_dbd); - epicsExit(status); +void usage(const char *arg0, const std::string& base_dbd) { + std::cout<<"Usage: "< 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 Access Security configuration file. Macro substitution is\n" + " performed.\n" + "\n" + " -m =,... Set/replace macro definitions used by subsequent -d and\n" + " -a.\n" + "\n" + " -d Load records from file (dbLoadRecords). Macro substitution is\n" + " performed.\n" + "\n" + " -x Load softIocExit.db. Provides a record \":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); - 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); - } - - softIoc_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: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: -"<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; }