1 /*----------------------------------------------------------------------------
  2 Name:      Properties.c
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   A tiny helper to encapsulate command line and environment properties
  6 Author:    "Marcel Ruff" <xmlBlaster@marcelruff.info>
  7 Compile:   gcc -DPropertiesMain -D_ENABLE_STACK_TRACE_ -rdynamic -export-dynamic -Wall -pedantic -g -D_REENTRANT -I.. -o PropertiesMain Properties.c
  8 See:       http://www.xmlblaster.org/xmlBlaster/doc/requirements/client.c.socket.html
  9 -----------------------------------------------------------------------------*/
 10 
 11 #include <stdio.h>
 12 #include <stdlib.h>
 13 #include <string.h>
 14 /*#include <errno.h>*/
 15 /*#include <sys/types.h>*/
 16 #include "helper.h"
 17 #include "Properties.h"
 18 
 19 static const char *getString(Properties *props, const char *key, const char *defaultValue);
 20 static bool getBool(Properties *props, const char *key, bool defaultValue);
 21 static int getInt(Properties *props, const char *key, int defaultValue);
 22 static long getLong(Properties *props, const char *key, long defaultValue);
 23 static int64_t getInt64(Properties *props, const char *key, int64_t defaultValue);
 24 static double getDouble(Properties *props, const char *key, double defaultValue);
 25 
 26 /**
 27  * Create an instance of a property struct.
 28  * NOTE: Our properties point on the passed argv memory, so you should
 29  * not free the original argv memory.
 30  * @param argc The number of command line args
 31  * @param argv The command line arguments, argv[0] is expected to be the
 32  *             name of the process, argv[1] should start with '-' and
 33  *             argv[2] is the value of the argv[1] key ...
 34  *             argv can be NULL if argc == 0
 35  */
 36 Properties *createProperties(int argc, const char* const* argv) {
 37    int iarg;
 38    Properties *props = (Properties *)calloc(1, sizeof(Properties));
 39    props->argc = 0;
 40    props->argv = 0;
 41    props->execName = (argv != 0) ? argv[0] : __FILE__;
 42    props->getString = getString;
 43    props->getBool = getBool;
 44    props->getInt = getInt;
 45    props->getLong = getLong;
 46    props->getInt64 = getInt64;
 47    props->getDouble = getDouble;
 48 
 49    if (argc > 1) {
 50       /* strip the executable name and the dash '-' */
 51       props->argc = argc-1;
 52       props->argv = (char **)calloc((size_t)props->argc, sizeof(char *));
 53       for (iarg=1; iarg < argc; iarg++) {
 54          if (argv[iarg] == 0 || strlen(argv[iarg]) == 0)
 55             props->argv[iarg-1] = (char *)argv[iarg];
 56          else if ((iarg % 2) == 1 && *argv[iarg] == '-')
 57             props->argv[iarg-1] = (char *)argv[iarg]+1;
 58          else
 59             props->argv[iarg-1] = (char *)argv[iarg];
 60       }
 61    }
 62    return props;
 63 }
 64 
 65 void freeProperties(Properties *props)
 66 {
 67    if (props == 0) return;
 68 
 69    if (props->argc > 0) {
 70       free(props->argv);
 71       props->argc = 0;
 72       props->argv = 0;
 73    }
 74    free(props);
 75 }
 76 
 77 /**
 78  * See header Properties.h for documentation
 79  */
 80 void dumpProperties(Properties *props)
 81 {
 82    int iarg;
 83    if (props == 0) return;
 84 
 85    for (iarg=0; iarg < props->argc-1; iarg++) {
 86       printf("#%d, %s=%s\n", iarg, props->argv[iarg], props->argv[iarg+1]);
 87       iarg++;
 88    }
 89 }
 90 
 91 /**
 92  * See header Properties.h for documentation
 93  */
 94 static const char *getString(Properties *props, const char *key, const char *defaultValue)
 95 {
 96    int iarg;
 97 
 98    if (props == 0 || key == 0) return defaultValue;
 99 
100    for (iarg=0; iarg < props->argc-1; iarg++) {
101       if (strcmp(props->argv[iarg], key) == 0)
102          return props->argv[++iarg];
103    }
104 
105 /*
106 WIN32
107    char *pValue;
108    size_t len;
109    errno_t err = _dupenv_s( &pValue, &len, "pathext" );
110    // returns 0 if not found!
111    if ( err ) return -1;
112    printf( "pathext = %s\n", pValue );
113    free( pValue );
114    err = _dupenv_s( &pValue, &len, "nonexistentvariable" );
115    if ( err ) return -1;
116    printf( "nonexistentvariable = %s\n", pValue );
117    free( pValue ); // It's OK to call free with NULL
118 
119    // not thread save as putenv could change
120    errno_t getenv_s(size_t *pReturnValue, char* buffer, size_t sizeInBytes, const char *varname);
121 
122 
123 UNIX: int getenv_r(const char *name, char *buf, size_t len);
124    returns -1 if not found
125 */
126 #if !defined(WINCE) /* Where is the getenv() for Windows CE? */
127    {
128       const char *p = getenv(key);
129       if (p != 0) return p;
130    }
131 #endif
132 
133    return defaultValue;
134 }
135 
136 static bool getBool(Properties *props, const char *key, bool defaultValue)
137 {
138    const char *valP = getString(props, key, 0);
139    if (valP != 0) {
140       if (!strcmp(valP, "false") || !strcmp(valP, "FALSE") || !strcmp(valP, "0"))
141          return false;
142       else
143          return true;
144    }
145    return defaultValue;
146 }
147 
148 static int getInt(Properties *props, const char *key, int defaultValue)
149 {
150    return (int)getLong(props, key, defaultValue);
151 }
152 
153 static long getLong(Properties *props, const char *key, long defaultValue)
154 {
155    const char *valP = getString(props, key, 0);
156    if (valP != 0) {
157       long val;
158       if (strToLong(&val, valP) == true)
159          return val;
160    }
161    return defaultValue;
162 }
163 
164 static int64_t getInt64(Properties *props, const char *key, int64_t defaultValue)
165 {
166    const char *valP = getString(props, key, 0);
167    if (valP != 0) {
168       int64_t val;
169       if (strToInt64(&val, valP) == true)
170          return val;
171    }
172    return defaultValue;
173 }
174 
175 static double getDouble(Properties *props, const char *key, double defaultValue)
176 {
177    const char *valP = getString(props, key, 0);
178    if (valP != 0) {
179       double val;
180       if (sscanf(valP, "%lf", &val) == 1)
181          return val;
182    }
183    return defaultValue;
184 }
185 
186 #ifdef PropertiesMain /* compile a standalone test program */
187 
188 Dll_Export bool strToInt64(int64_t *val, const char * const str) {
189    if (str == 0 || val == 0) return false;
190    return (SSCANF(str, PRINTF_PREFIX_INT64_T, val) == 1) ? true : false;
191 }
192 
193 /**
194  * icc -DPropertiesMain -Wall -g -I.. -o PropertiesMain Properties.c
195  * Invoke:
196  * export MY_SETTING="Hello World"
197  * PropertiesMain -logLevel TRACE  -numTests 10  -timeout -999 -isPersistent true -isDurable false
198  */
199 int main(int argc, char** argv)
200 {
201    Properties *props = createProperties(argc, (const char* const*)argv);
202    printf("MY_SETTING=%s\n", props->getString(props, "MY_SETTING", "DUMMY"));
203    printf("logLevel=%s\n", props->getString(props, "logLevel", "DUMMY"));
204    printf("isPersistent=%d\n", props->getBool(props, "isPersistent", false));
205    printf("isDurable=%d\n", props->getBool(props, "isDurable", true));
206    printf("numTests=%d\n", props->getInt(props, "numTests", -1));
207    printf("timeout=%ld\n", props->getLong(props, "timeout", -1l));
208    printf("timeout="PRINTF_PREFIX_INT64_T"\n", props->getInt64(props, "lonLong", -1LL)); /* "%I64d", "%ld", "%lld" */
209    freeProperties(props);
210    return 0;
211 }
212 #endif /* #ifdef PropertiesMain */


syntax highlighted by Code2HTML, v. 0.9.1