/* OSSP rc - Run-command processor ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 Cable & Wireless Deutschland GmbH ** Copyright (c) 2002 The OSSP Project ** ** This file is part of OSSP rc, a portable Run-command processor ** which can be found at http://www.ossp.org/pkg/lib/rc/ ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** rc_cliopt.c: Run-command processor ISO C source file */ #include #include #include "rc.h" #include "rc_const.h" #include "rc_config.h" #include "popt.h" /* OSSP popt options library */ static char *m_pszOptuples[RC_NUMOPTS]; /* Option name value tuples */ static char *m_szRcfile = NULL; /* rc file name */ static char **m_pszSecs = NULL; /* Section names */ static popt_context m_Optcon; /* Context for parsing options */ static struct popt_option m_pOptable[] = { /* Long options with short keys but no arguments */ {RC_USE_NAME, '?', POPT_ARG_NONE, 0, RC_USE_VAL, RC_USE_DESC, NULL}, {RC_DBG_NAME, 'd', POPT_ARG_NONE, 0, RC_DBG_VAL, RC_DBG_DESC, NULL}, {RC_VER_NAME, 'V', POPT_ARG_NONE, 0, RC_VER_VAL, RC_VER_DESC, NULL}, {RC_EVL_NAME, 'e', POPT_ARG_NONE, 0, RC_EVL_VAL, RC_EVL_DESC, NULL}, {RC_HLP_NAME, 'h', POPT_ARG_NONE, 0, RC_HLP_VAL, RC_HLP_DESC, NULL}, {RC_INF_NAME, 'i', POPT_ARG_NONE, 0, RC_INF_VAL, RC_INF_DESC, NULL}, {RC_LBL_NAME, 'l', POPT_ARG_NONE, 0, RC_LBL_VAL, RC_LBL_DESC, NULL}, {RC_PRN_NAME, 'p', POPT_ARG_NONE, 0, RC_PRN_VAL, RC_PRN_DESC, NULL}, {RC_SIL_NAME, 's', POPT_ARG_NONE, 0, RC_SIL_VAL, RC_SIL_DESC, NULL}, {RC_RAW_NAME, 'r', POPT_ARG_NONE, 0, RC_RAW_VAL, RC_RAW_DESC, NULL}, {RC_VRB_NAME, 'v', POPT_ARG_NONE, 0, RC_VRB_VAL, RC_VRB_DESC, NULL}, {RC_EXC_NAME, 'x', POPT_ARG_NONE, 0, RC_EXC_VAL, RC_EXC_DESC, NULL}, /* Single argument long options with short keys */ {RC_LOC_NAME, 'L', POPT_ARG_STRING, 0, RC_LOC_VAL, RC_LOC_DESC, "regx"}, {RC_CNF_NAME, 'c', POPT_ARG_STRING, 0, RC_CNF_VAL, RC_CNF_DESC, "path"}, {RC_FNC_NAME, 'f', POPT_ARG_STRING, 0, RC_FNC_VAL, RC_FNC_DESC, "path"}, {RC_QRY_NAME, 'q', POPT_ARG_STRING, 0, RC_QRY_VAL, RC_QRY_DESC, "varx"}, {RC_TMP_NAME, 't', POPT_ARG_STRING, 0, RC_TMP_VAL, RC_TMP_DESC, "path"}, /* Single argument long options without short keys */ {RC_OWN_NAME, 0, POPT_ARG_STRING, 0, RC_OWN_VAL, RC_OWN_DESC, "user"}, {RC_GRP_NAME, 0, POPT_ARG_STRING, 0, RC_GRP_VAL, RC_GRP_DESC, "group"}, {RC_MSK_NAME, 0, POPT_ARG_INT, 0, RC_MSK_VAL, RC_MSK_DESC, "umask"}, {RC_ASS_NAME, 0, POPT_ARG_STRING, 0, RC_ASS_VAL, RC_ASS_DESC, "regx"}, {RC_DEF_NAME, 0, POPT_ARG_STRING, 0, RC_DEF_VAL, RC_DEF_DESC, "regx"}, {RC_REF_NAME, 0, POPT_ARG_STRING, 0, RC_REF_VAL, RC_REF_DESC, "regx"}, {RC_PRM_NAME, 0, POPT_ARG_STRING, 0, RC_PRM_VAL, RC_PRM_DESC, "regx"}, {RC_TRM_NAME, 0, POPT_ARG_STRING, 0, RC_TRM_VAL, RC_TRM_DESC, "regx"}, {RC_NCF_NAME, 0, POPT_ARG_STRING, 0, RC_NCF_VAL, RC_NCF_DESC, "name"}, {RC_CMN_NAME, 0, POPT_ARG_STRING, 0, RC_CMN_VAL, RC_CMN_DESC, "name"}, {RC_DFL_NAME, 0, POPT_ARG_STRING, 0, RC_DFL_VAL, RC_DFL_DESC, "name"}, {RC_ERR_NAME, 0, POPT_ARG_STRING, 0, RC_ERR_VAL, RC_ERR_DESC, "name"}, /* Special stuff */ POPT_AUTOHELP {NULL, 0, 0, NULL, 0} }; /*************************************** * clioptNew(void) * * Construct a command line option * ***************************************/ rc_return_t clioptNew(void) { /* assert(s_pBintab == NULL); */ /* Error if constructed already */ /* s_pBintab = malloc(sizeof(*s_pBintab));*/ /* Allocate a cliopt instance */ /* if (!s_pBintab) return(RC_THROW(RC_ERR_MEM)); s_pBintab->pOptlist = malloc(sizeof(*s_pBintab->pOptlist));*/ /*FIXME optNew((rc_opt_t **)&s_pBintab->pOptlist->pvData);FIXME*/ /* s_pBintab->pOptlist->pvData = NULL; s_pBintab->pOptlist->pvNext = NULL;*/ memset(m_pszOptuples, NULL, sizeof(m_pszOptuples)); return(RC_THROW(RC_OK)); } /*************************************** * clioptPrintusage() * * Print usage to command line stderr * ***************************************/ rc_return_t clioptPrintusage(void) { popt_printusage(m_Optcon, stderr, 0); return(RC_THROW(RC_OK)); } /*************************************** * clioptGetXXX() * * clioptSetXXX() * * Command line option accessors * ***************************************/ const char *clioptGetval(rc_opt_t Optname) { if (!(Optname < RC_NUMOPTS)) /* Validate option range */ RC_THROW(RC_ERR_USE); return((const char *)m_pszOptuples[Optname]); } const char *clioptGetrcfile(void) { if (!m_szRcfile) RC_THROW(RC_ERR_USE); return((const char *)m_szRcfile); } const char **clioptGetsecs(void) { if (!m_pszSecs) RC_THROW(RC_ERR_USE); return((const char **)m_pszSecs); } rc_return_t clioptSetval(rc_opt_t Optname, const char *kszOptval) { if (!(Optname < RC_NUMOPTS)) /* Validate option range */ return(RC_THROW(RC_ERR_USE)); if (!(kszOptval)) /* Validate string value */ return(RC_THROW(RC_ERR_USE)); if (!(m_pszOptuples[Optname] = strdup(kszOptval))) return(RC_THROW(RC_ERR_MEM)); return(RC_THROW(RC_OK)); } rc_return_t clioptSetrcfile(const char *kszRc) { if (m_szRcfile) /* Warn on overwrites */ RC_THROW(RC_WRN_OWR); if (kszRc) m_szRcfile = strdup(kszRc); else return(RC_THROW(RC_ERR_USE)); /* Incoming string is NULL? */ return(RC_THROW(RC_OK)); } rc_return_t clioptSetsecs(const char **pkszSecs) { int nSecs = 0; int nIndex = 0; if (m_pszSecs) /* Warn on overwrites */ RC_THROW(RC_WRN_OWR); if (pkszSecs) { for (nSecs = 0; pkszSecs[nSecs]; nSecs++); /* Count the sections */ m_pszSecs = malloc(sizeof (char **) * nSecs + 1); for (nIndex = 0; pkszSecs[nIndex]; nIndex++) { m_pszSecs[nIndex] = malloc(strlen(pkszSecs[nIndex])); memcpy(m_pszSecs[nIndex], pkszSecs[nIndex],\ strlen(pkszSecs[nIndex])); } m_pszSecs[nIndex] = NULL; /* Used later to find the end of the array */ } else return(RC_THROW(RC_ERR_USE)); /* Incoming sections are NULL? */ return(RC_THROW(RC_OK)); } /*************************************** * clioptProcess(int) * * Switch through available options * * processing the corresponding option * * and update option table accordingly * ***************************************/ rc_return_t clioptProcess(int cliOption, const char *kszArg) { switch (cliOption) { /* Begin concrete (digital) options */ case RC_USE_VAL: clioptSetval(cliOption, "1"); break; /* Usage */ case RC_DBG_VAL: clioptSetval(cliOption, "1"); break; /* Debug */ case RC_VER_VAL: clioptSetval(cliOption, "1"); break; /* Version */ case RC_EVL_VAL: clioptSetval(cliOption, "1"); break; /* Eval */ case RC_HLP_VAL: clioptSetval(cliOption, "1"); break; /* Help */ case RC_INF_VAL: clioptSetval(cliOption, "1"); break; /* Info */ case RC_LBL_VAL: clioptSetval(cliOption, "1"); break; /* Label */ case RC_PRN_VAL: clioptSetval(cliOption, "1"); break; /* Print */ case RC_SIL_VAL: clioptSetval(cliOption, "1"); break; /* Silent */ case RC_RAW_VAL: clioptSetval(cliOption, "1"); break; /* Raw */ case RC_VRB_VAL: clioptSetval(cliOption, "1"); break; /* Verbose */ case RC_EXC_VAL: clioptSetval(cliOption, "1"); break; /* Exec */ /* Begin abstract (nondigital) options */ case RC_LOC_VAL: clioptSetval(cliOption, kszArg); break; /* Locations */ case RC_CNF_VAL: clioptSetval(cliOption, kszArg); break; /* Conf file */ case RC_FNC_VAL: clioptSetval(cliOption, kszArg); break; /* Func file */ case RC_QRY_VAL: clioptSetval(cliOption, kszArg); break; /* Format */ case RC_TMP_VAL: clioptSetval(cliOption, kszArg); break; /* Temp dir */ case RC_OWN_VAL: clioptSetval(cliOption, kszArg); break; /* User name */ case RC_GRP_VAL: clioptSetval(cliOption, kszArg); break; /* Group name */ case RC_MSK_VAL: clioptSetval(cliOption, kszArg); break; /* Umask */ case RC_ASS_VAL: clioptSetval(cliOption, kszArg); break; /* Assignregex */ case RC_DEF_VAL: clioptSetval(cliOption, kszArg); break; /* Labelregex */ case RC_REF_VAL: clioptSetval(cliOption, kszArg); break; /* Refregex */ case RC_PRM_VAL: clioptSetval(cliOption, kszArg); break; /* Paramregex */ case RC_TRM_VAL: clioptSetval(cliOption, kszArg); break; /* Termregex */ case RC_NCF_VAL: clioptSetval(cliOption, kszArg); break; /* Configname */ case RC_CMN_VAL: clioptSetval(cliOption, kszArg); break; /* Commonname */ case RC_DFL_VAL: clioptSetval(cliOption, kszArg); break; /* Defaultname */ case RC_ERR_VAL: clioptSetval(cliOption, kszArg); break; /* Errorname */ default : break; } return(RC_THROW(RC_OK)); } /*************************************** * clioptParseopts(int, const char **) * * Parse command line options * ***************************************/ rc_return_t clioptParseopts(int nArgs, const char *szVector[]) { ex_t Except; char cliOpt = 0; /* For argument parsing */ m_Optcon = popt_getcontext(NULL, nArgs, szVector, m_pOptable, 0); popt_setotheroptionhelp(m_Optcon, " "); if (nArgs < 2) { /* Allow the user to enter just one option, -h z.B. */ fprintf(stderr, RC_LST_TEXT); popt_printusage(m_Optcon, stderr, 0); return(RC_THROW(RC_ERR_USE)); } /* Now do options processing */ while ((cliOpt = popt_getnextopt(m_Optcon)) >= 0) {/* Loop, each time */ ex_try { /* eating a new option */ clioptProcess(cliOpt, popt_getoptarg(m_Optcon)); } ex_catch(Except) { /* Error condition probably deserves attention */ rethrow; } } if (cliOpt < -1) { /* An error occurred during option processing */ fprintf(stderr, "%s: %s\n", popt_badoption(m_Optcon, POPT_BADOPTION_NOALIAS), popt_strerror(cliOpt)); return(RC_THROW(RC_ERR_INT)); } return(RC_THROW(RC_OK)); } /****************************************** * clioptParseargs(void) * * Parse command line rc file and sections * ******************************************/ rc_return_t clioptParseargs(void) { ex_t Except; /* Use popt as a transport to read the user specified rcfile and sections */ ex_try { clioptSetrcfile(popt_getarg(m_Optcon)); clioptSetsecs(popt_getargs(m_Optcon)); } ex_catch(Except) { rethrow; /* Our generic response */ } return(RC_THROW(RC_OK)); } /*************************************** * clioptDelete(void) * * Destruct a command line option * ***************************************/ rc_return_t clioptDelete(void) { int i = 0; /* ex_t Except; assert(s_pBintab);*/ /* Error if not constructed */ /* ex_try { clioptRemall();*/ /* Removes ALL list nodes */ /*FIXME optDelete((rc_opt_t **)&s_pBintab->pOptlist->pvData);FIXME*/ /* free(s_pBintab->pOptlist);*/ /* Deallocate option list */ /* free(s_pBintab);*/ /* Deallocate cliopt and */ /* s_pBintab = NULL;*/ /* clear its reference */ /* } ex_catch(Except) { rethrow; }*/ popt_freecontext(m_Optcon); /* Free the popt context */ for (i = 0; i < RC_NUMOPTS; i++) { /* Free the tuples themselves */ if (m_pszOptuples[i]) { free(m_pszOptuples[i]); m_pszOptuples[i] = NULL; } } if (m_szRcfile) /* Free the rc file arg */ free(m_szRcfile); if (m_pszSecs) { /* Free the section name arg */ for (i = 0; m_pszSecs[i]; i++) { free(m_pszSecs[i]); m_pszSecs[i] = NULL; } free(m_pszSecs); } /* FIXME BEGIN DEBUG */ for (i = 0; i < RC_NUMOPTS; i++) if (m_pszOptuples[i]) TRACE("Problem! Destructor failed!\n"); /* FIXME END DEBUG */ return(RC_THROW(RC_OK)); }