Browse Source

Implement config file

Serj Kalichev 6 years ago
parent
commit
67b48c72a6
10 changed files with 956 additions and 60 deletions
  1. 132 59
      birq.c
  2. 128 0
      lub/ctype.h
  3. 35 0
      lub/ctype/ctype.c
  4. 2 0
      lub/ctype/module.am
  5. 8 1
      lub/module.am
  6. 279 0
      lub/string.h
  7. 4 0
      lub/string/module.am
  8. 4 0
      lub/string/private.h
  9. 340 0
      lub/string/string.c
  10. 24 0
      lub/types.h

+ 132 - 59
birq.c

@@ -27,6 +27,7 @@
 #include "birq.h"
 #include "lub/log.h"
 #include "lub/list.h"
+#include "lub/ini.h"
 #include "irq.h"
 #include "numa.h"
 #include "cpu.h"
@@ -51,6 +52,8 @@ static int parse_config(const char *fname, struct options *opts);
 /* Command line options */
 struct options {
 	char *pidfile;
+	char *cfgfile;
+	int cfgfile_userdefined;
 	char *pxm; /* Proximity config file */
 	int debug; /* Don't daemonize in debug mode */
 	int log_facility;
@@ -91,6 +94,22 @@ int main(int argc, char **argv)
 	if (opts_parse(argc, argv, opts))
 		goto err;
 
+	/* Parse config file */
+	if (!access(opts->cfgfile, R_OK)) {
+		if (parse_config(opts->cfgfile, opts))
+			goto err;
+	} else if (opts->cfgfile_userdefined) {
+		fprintf(stderr, "Error: Can't find config file %s\n",
+			opts->cfgfile);
+		goto err;
+	}
+
+	/* Validate threshold and load limit */
+	if (opts->load_limit > opts->threshold) {
+		fprintf(stderr, "Error: The load limit is greater than threshold.\n");
+		goto err;
+	}
+
 	/* Initialize syslog */
 	openlog(argv[0], LOG_CONS, opts->log_facility);
 	syslog(LOG_ERR, "Start daemon.\n");
@@ -253,6 +272,8 @@ static struct options *opts_init(void)
 	assert(opts);
 	opts->debug = 0; /* daemonize by default */
 	opts->pidfile = strdup(BIRQ_PIDFILE);
+	opts->cfgfile = strdup(BIRQ_CFGFILE);
+	opts->cfgfile_userdefined = 0;
 	opts->pxm = NULL;
 	opts->log_facility = LOG_DAEMON;
 	opts->threshold = BIRQ_DEFAULT_THRESHOLD;
@@ -272,20 +293,82 @@ static void opts_free(struct options *opts)
 {
 	if (opts->pidfile)
 		free(opts->pidfile);
+	if (opts->cfgfile)
+		free(opts->cfgfile);
 	if (opts->pxm)
 		free(opts->pxm);
 	free(opts);
 }
 
+/* Parse 'strategy' option */
+static int opt_parse_strategy(const char *optarg, birq_choose_strategy_e *strategy)
+{
+	assert(optarg);
+	assert(strategy);
+
+	if (!strcmp(optarg, "max"))
+		*strategy = BIRQ_CHOOSE_MAX;
+	else if (!strcmp(optarg, "min"))
+		*strategy = BIRQ_CHOOSE_MIN;
+	else if (!strcmp(optarg, "rnd"))
+		*strategy = BIRQ_CHOOSE_RND;
+	else {
+		fprintf(stderr, "Error: Illegal strategy value %s.\n", optarg);
+		return -1;
+	}
+	return 0;
+}
+
+/* Parse 'threshold' and 'load-limit' options */
+static int opt_parse_threshold(const char *optarg, float *threshold)
+{
+	char *endptr;
+	float thresh;
+
+	assert(optarg);
+	assert(threshold);
+
+	thresh = strtof(optarg, &endptr);
+	if (endptr == optarg) {
+		fprintf(stderr, "Error: Illegal threshold/load-limit value %s.\n", optarg);
+		return -1;
+	}
+	if (thresh > 100.00) {
+		fprintf(stderr, "Error: The threshold/load-limit value %s > 100.\n", optarg);
+		return -1;
+	}
+	*threshold = thresh;
+	return 0;
+}
+
+/* Parse 'short-interval' and 'long-interval' options */
+static int opt_parse_interval(const char *optarg, unsigned int *interval)
+{
+	char *endptr;
+	unsigned long int val;
+
+	assert(optarg);
+	assert(interval);
+
+	val = strtoul(optarg, &endptr, 10);
+	if (endptr == optarg) {
+		fprintf(stderr, "Error: Illegal interval value %s.\n", optarg);
+		return -1;
+	}
+	*interval = val;
+	return 0;
+}
+
 /*--------------------------------------------------------- */
 /* Parse command line options */
 static int opts_parse(int argc, char *argv[], struct options *opts)
 {
-	static const char *shortopts = "hp:dO:t:l:vri:I:s:x:";
+	static const char *shortopts = "hp:c:dO:t:l:vri:I:s:x:";
 #ifdef HAVE_GETOPT_H
 	static const struct option longopts[] = {
 		{"help",		0, NULL, 'h'},
 		{"pid",			1, NULL, 'p'},
+		{"conf",		1, NULL, 'c'},
 		{"debug",		0, NULL, 'd'},
 		{"facility",		1, NULL, 'O'},
 		{"threshold",		1, NULL, 't'},
@@ -293,7 +376,7 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 		{"verbose",		0, NULL, 'v'},
 		{"ht",			0, NULL, 'r'},
 		{"short-interval",	1, NULL, 'i'},
-		{"long-interval",	1, NULL, 'i'},
+		{"long-interval",	1, NULL, 'I'},
 		{"strategy",		1, NULL, 's'},
 		{"pxm",			1, NULL, 'x'},
 		{NULL,			0, NULL, 0}
@@ -315,6 +398,12 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 				free(opts->pidfile);
 			opts->pidfile = strdup(optarg);
 			break;
+		case 'c':
+			if (opts->cfgfile)
+				free(opts->cfgfile);
+			opts->cfgfile = strdup(optarg);
+			opts->cfgfile_userdefined = 1;
+			break;
 		case 'x':
 			if (opts->pxm)
 				free(opts->pxm);
@@ -332,70 +421,28 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 		case 'O':
 			if (lub_log_facility(optarg, &(opts->log_facility))) {
 				fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
-				help(-1, argv[0]);
 				exit(-1);
 			}
 			break;
 		case 't':
-			{
-			char *endptr;
-			float thresh;
-			thresh = strtof(optarg, &endptr);
-			if (endptr == optarg)
-				thresh = opts->threshold;
-			opts->threshold = thresh;
-			if (thresh > 100.00) {
-				fprintf(stderr, "Error: Illegal threshold value %s.\n", optarg);
-				help(-1, argv[0]);
+			if (opt_parse_threshold(optarg, &opts->threshold))
 				exit(-1);
-			}
-			}
 			break;
 		case 'l':
-			{
-			char *endptr;
-			float limit;
-			limit = strtof(optarg, &endptr);
-			if (endptr == optarg)
-				limit = opts->load_limit;
-			opts->load_limit = limit;
-			if (limit > 100.00) {
-				fprintf(stderr, "Error: Illegal load limit value %s.\n", optarg);
-				help(-1, argv[0]);
+			if (opt_parse_threshold(optarg, &opts->load_limit))
 				exit(-1);
-			}
-			}
 			break;
 		case 'i':
-			{
-			char *endptr;
-			unsigned long int val;
-			val = strtoul(optarg, &endptr, 10);
-			if (endptr != optarg)
-				opts->short_interval = val;
-			}
+			if (opt_parse_interval(optarg, &opts->short_interval))
+				exit(-1);
 			break;
 		case 'I':
-			{
-			char *endptr;
-			unsigned long int val;
-			val = strtoul(optarg, &endptr, 10);
-			if (endptr != optarg)
-				opts->long_interval = val;
-			}
+			if (opt_parse_interval(optarg, &opts->long_interval))
+				exit(-1);
 			break;
 		case 's':
-			if (!strcmp(optarg, "max"))
-				opts->strategy = BIRQ_CHOOSE_MAX;
-			else if (!strcmp(optarg, "min"))
-				opts->strategy = BIRQ_CHOOSE_MIN;
-			else if (!strcmp(optarg, "rnd"))
-				opts->strategy = BIRQ_CHOOSE_RND;
-			else {
-				fprintf(stderr, "Error: Illegal strategy value %s.\n", optarg);
-				help(-1, argv[0]);
+			if (opt_parse_strategy(optarg, &opts->strategy) < 0)
 				exit(-1);
-			}
 			break;
 		case 'h':
 			help(0, argv[0]);
@@ -408,12 +455,6 @@ static int opts_parse(int argc, char *argv[], struct options *opts)
 		}
 	}
 
-	/* Check threshold and load limit */
-	if (opts->load_limit > opts->threshold) {
-		fprintf(stderr, "Error: The load limit is greater than threshold.\n");
-		help(-1, argv[0]);
-		exit(-1);
-	}
 
 	return 0;
 }
@@ -446,9 +487,10 @@ static void help(int status, const char *argv0)
 		printf("\t-d, --debug Debug mode. Don't daemonize.\n");
 		printf("\t-v, --verbose Be verbose.\n");
 		printf("\t-r, --ht Enable Hyper Threading.\n");
-		printf("\t-p <path>, --pid=<path> File to save daemon's PID to.\n");
+		printf("\t-p <path>, --pid=<path> File to save daemon's PID to (" BIRQ_PIDFILE ").\n");
+		printf("\t-c <path>, --conf=<path> Config file (" BIRQ_CFGFILE ").\n");
 		printf("\t-x <path>, --pxm=<path> Proximity config file.\n");
-		printf("\t-O, --facility Syslog facility. Default is DAEMON.\n");
+		printf("\t-O, --facility Syslog facility (DAEMON).\n");
 		printf("\t-t <float>, --threshold=<float> Threshold to consider CPU is overloaded, in percents. Default threhold is %.2f.\n",
 			BIRQ_DEFAULT_THRESHOLD);
 		printf("\t-l <float>, --load-limit=<float> Don't move IRQs to CPUs loaded more than this limit, in percents. Default limit is %.2f.\n",
@@ -463,6 +505,37 @@ static void help(int status, const char *argv0)
 /* Parse config file */
 static int parse_config(const char *fname, struct options *opts)
 {
+	lub_ini_t *ini;
+	const char *tmp = NULL;
+
+	ini = lub_ini_new();
+	if (lub_ini_parse_file(ini, opts->cfgfile)) {
+		lub_ini_free(ini);
+		return -1;
+	}
+
+	if ((tmp = lub_ini_find(ini, "strategy")))
+		if (opt_parse_strategy(tmp, &opts->strategy) < 0)
+			goto err;
+
+	if ((tmp = lub_ini_find(ini, "threshold")))
+		if (opt_parse_threshold(tmp, &opts->threshold))
+			goto err;
+
+	if ((tmp = lub_ini_find(ini, "load-limit")))
+		if (opt_parse_threshold(tmp, &opts->load_limit))
+			goto err;
+
+	if ((tmp = lub_ini_find(ini, "short-interval")))
+		if (opt_parse_interval(tmp, &opts->short_interval))
+			goto err;
+
+	if ((tmp = lub_ini_find(ini, "long-interval")))
+		if (opt_parse_interval(tmp, &opts->long_interval))
+			goto err;
 
 	return 0;
+err:
+	lub_ini_free(ini);
+	return -1;
 }

+ 128 - 0
lub/ctype.h

@@ -0,0 +1,128 @@
+/*
+ * ctype.h
+ */
+/**
+\ingroup lub
+\defgroup lub_ctype ctype
+@{
+
+\brief The ANSI-C standard <ctype.h> interface works fine for strings 
+containing characters encoded with the ASCII 7-bit coding. However 
+when you use characters outside this range things start to get ambiguous. 
+
+The default manner in which to represent a string in C is to use a 
+"char *". (NB. this is a signed type) The interfaces presented 
+in <ctype.h> take signed integers. When a character greater than 128 is
+passed as a "char" to isspace() (e.g. the british pound sign "£") then 
+a negative value is passed into the function/macro. A typical
+implementation (e.g. VxWorks) may use the passed argument as an offset
+into a lookup table, negative values in this case cause problems...
+
+This utility provides an interface which avoids this ambiguity by passing 
+"char" characters directly rather than converting to "int".
+
+This component currently only contains those operations which are required
+by the current CLISH/LUB implementations. It can be extended on an as needed 
+basis.
+
+*/
+/*---------------------------------------------------------------
+ * HISTORY
+ * 4-Sep-2006		Graeme McKerrell	
+ *    Initial Version
+ *---------------------------------------------------------------
+ * Copyright (C) 2006 Newport Networks. All Rights Reserved.
+ *--------------------------------------------------------------- */
+#ifndef _lub_ctype_h
+#define _lub_ctype_h
+
+#include <ctype.h>
+
+#include "lub/types.h"
+#include "lub/c_decl.h"
+
+_BEGIN_C_DECL
+/**
+ * This operation identifies whether a character is a decimal digit
+ * or not.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * BOOL_TRUE  - if the character is a decimal digit
+ * BOOL_FALSE - if the character is not a decimal digit
+ *
+ * \post 
+ * - none
+ */
+bool_t lub_ctype_isdigit(
+	/** 
+         * The character to check
+         */
+				char c);
+/**
+ * This operation identifies whether a character is a standard white space
+ * character. (space, tab, carriage-return, vertical tab, form-feed)
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * BOOL_TRUE  - if the character is white space
+ * BOOL_FALSE - if the character is not white space
+ *
+ * \post 
+ * - none
+ */
+bool_t lub_ctype_isspace(
+	/** 
+         * The character to check
+         */
+				char c);
+/**
+ * This operation converts an uppercase letter to the corresponding 
+ * lowercase letter.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * If the parameter is a character for which lub_ctype_isupper() is true 
+ * and there is a corresponding character for which lub_ctype_islower() is true
+ * then the corresponding character is returned. Otherwise the parameter is 
+ * returned unchanged.
+ *
+ * \post 
+ * - none
+ */
+char lub_ctype_tolower(
+	/** 
+         * The character to convert
+         */
+			      char c);
+/**
+ * This operation converts a lowercase letter to the corresponding 
+ * uppercase letter.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * If the parameter is a character for which lub_ctype_islower() is true 
+ * and there is a corresponding character for which lub_ctype_isupper() is true
+ * then the corresponding character is returned. Otherwise the parameter is 
+ * returned unchanged.
+ *
+ * \post 
+ * - none
+ */
+char lub_ctype_toupper(
+	/** 
+         * The character to convert
+         */
+			      char c);
+
+_END_C_DECL
+#endif				/* _lub_ctype_h */
+/** @} */

+ 35 - 0
lub/ctype/ctype.c

@@ -0,0 +1,35 @@
+/*
+ * ctype.c
+ */
+#include "lub/ctype.h"
+#include <ctype.h>
+
+/*--------------------------------------------------------- */
+bool_t lub_ctype_isdigit(char c)
+{
+	unsigned char tmp = (unsigned char)c;
+	return isdigit(tmp) ? BOOL_TRUE : BOOL_FALSE;
+}
+
+/*--------------------------------------------------------- */
+bool_t lub_ctype_isspace(char c)
+{
+	unsigned char tmp = (unsigned char)c;
+	return isspace(tmp) ? BOOL_TRUE : BOOL_FALSE;
+}
+
+/*--------------------------------------------------------- */
+char lub_ctype_tolower(char c)
+{
+	unsigned char tmp = (unsigned char)c;
+	return tolower(tmp);
+}
+
+/*--------------------------------------------------------- */
+char lub_ctype_toupper(char c)
+{
+	unsigned char tmp = (unsigned char)c;
+	return toupper(tmp);
+}
+
+/*--------------------------------------------------------- */

+ 2 - 0
lub/ctype/module.am

@@ -0,0 +1,2 @@
+liblub_a_SOURCES += lub/ctype/ctype.c
+

+ 8 - 1
lub/module.am

@@ -6,14 +6,21 @@ noinst_HEADERS += \
     lub/list.h \
     lub/c_decl.h \
     lub/log.h \
-    lub/ini.h
+    lub/ini.h \
+    lub/string.h \
+    lub/types.h \
+    lub/ctype.h
 
 EXTRA_DIST +=   \
     lub/list/module.am \
     lub/log/module.am \
     lub/ini/module.am \
+    lub/string/module.am \
+    lub/ctype/module.am \
     lub/README
 
 include $(top_srcdir)/lub/list/module.am
 include $(top_srcdir)/lub/log/module.am
 include $(top_srcdir)/lub/ini/module.am
+include $(top_srcdir)/lub/string/module.am
+include $(top_srcdir)/lub/ctype/module.am

+ 279 - 0
lub/string.h

@@ -0,0 +1,279 @@
+/*
+ * string.h
+ */
+/**
+\ingroup lub
+\defgroup lub_string string
+@{
+
+\brief This utility provides some simple string manipulation functions which
+augment those found in the standard ANSI-C library.
+
+As a rule of thumb if a function returns "char *" then the calling client becomes responsible for invoking 
+lub_string_free() to release the dynamically allocated memory.
+
+If a "const char *" is returned then the client has no responsiblity for releasing memory.
+*/
+/*---------------------------------------------------------------
+ * HISTORY
+ * 7-Dec-2004		Graeme McKerrell	
+ *    Updated to use the "lub" prefix
+ * 6-Feb-2004		Graeme McKerrell	
+ *    removed init_fn type definition and parameter, the client had
+ *    more flexiblity in defining their own initialisation operation with
+ *    arguments rather than use a "one-size-fits-all" approach.
+ *    Modified blockpool structure to support FIFO block allocation.
+ * 23-Jan-2004		Graeme McKerrell	
+ *    Initial version
+ *---------------------------------------------------------------
+ * Copyright (C) 2004 3Com Corporation. All Rights Reserved.
+ *--------------------------------------------------------------- */
+#ifndef _lub_string_h
+#define _lub_string_h
+
+#include <stddef.h>
+
+#include "lub/c_decl.h"
+#include "lub/types.h"
+
+#define UTF8_MASK 0xC0
+#define UTF8_7BIT_MASK 0x80 /* One byte or multibyte */
+#define UTF8_11   0xC0 /* First UTF8 byte */
+#define UTF8_10   0x80 /* Next UTF8 bytes */
+
+_BEGIN_C_DECL
+/**
+ * This operation duplicates the specified string.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * A dynamically allocated string containing the same content as that specified.
+ *
+ * \post 
+ * - The client is responsible for calling lub_string_free() with the
+ *   returned string when they are finished using it.
+ */
+char *lub_string_dup(
+	/** 
+         * The string to duplicate
+         */
+			    const char *string);
+/**
+ * This operation concatinates the specified text onto an existing string.
+ *
+ * \pre 
+ * - 'string_ptr' must contain reference to NULL or to a dynamically 
+ *   allocated string.
+ * 
+ * \post 
+ * - The old string referenced by 'string_ptr' will be automatically released
+ * - 'string_ptr' will be updated to point to a dynamically allocated string 
+ *   containing the concatinated text.
+ * - If there is insufficient resource to extend the string then it will not
+ *   be extended.
+ * - The client maintains responsibility for releasing the string reference
+ *   by string_ptr when they are finished using it.
+ */
+void lub_string_cat(
+	/** 
+         * A pointer to the string to concatinate
+         */
+			   char **string_ptr,
+	/** 
+         * The text to be appended
+         */
+			   const char *text);
+/**
+ * This operation concatinates a specified length of some text onto an
+ * existing string.
+ *
+ * \pre 
+ * - 'string_ptr' must contain reference to NULL or to a dynamically allocated
+ *   string.
+ * 
+ * \post 
+ * - The old string referenced by 'string_ptr' will be automatically
+ *   released.
+ * - 'string_ptr' will be updated to point to a dynamically allocated
+ *   string containing the concatinated text.
+ * - If there is insufficient resource to extend the string then it will not
+ *   be extended.
+ * - If there length passed in is greater than that of the specified 'text'
+ *   then the length of the 'text' will be assumed.
+ * - The client maintains responsibility for releasing the string reference
+ *   by string_ptr when they are finished using it.
+ */
+void lub_string_catn(
+	/** 
+         * A pointer to the string to concatinate
+         */
+			    char **string_ptr,
+	/** 
+         * The text to be appended
+         */
+			    const char *text,
+	/** 
+         * The length of text to be appended
+         */
+			    size_t length);
+/**
+ * This operation dupicates a specified length of some text into a
+ * new string.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * A dynamically allocated string containing the same content as that specified.
+ *
+ * \post 
+ * - The client is responsible for calling lub_string_free() with the
+ *   returned string when they are finished using it.
+ */
+char *lub_string_dupn(
+	/** 
+         * The string containing the text to duplicate
+         */
+			     const char *string,
+	/** 
+         * The length of text to be duplicated
+         */
+			     unsigned length);
+/**
+ * This operation returns a pointer to the last (space separated) word in the
+ * specified string.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * A pointer to the last word in the string.
+ *
+ * \post 
+ * - none
+ */
+const char *lub_string_suffix(
+	/**
+         * The string from which to extract a suffix 
+         */
+				     const char *string);
+
+/**
+ * This operation compares string cs to string ct in a case insensitive manner.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return 
+ * - < 0 if cs < ct
+ * -   0 if cs == ct
+ * - > 0 if cs > ct
+ *
+ * \post 
+ * - none
+ */
+int lub_string_nocasecmp(
+	/**
+         * The first string for the comparison
+         */
+				const char *cs,
+	/**
+         * The second string for the comparison 
+         */
+				const char *ct);
+/**
+ * This operation performs a case insensitive search for a substring within
+ * another string.
+ *
+ * \pre 
+ * - none
+ * 
+ * \return
+ * pointer to first occurance of a case insensitive version of the string ct, 
+ * or NULL if not present.
+ *
+ * \post 
+ * - none
+ */
+const char *lub_string_nocasestr(
+	/**
+         * The string within which to find a substring
+         */
+					const char *cs,
+	/**
+         * The substring for which to search
+         */
+					const char *ct);
+
+/**
+ * This operation releases the resources associated with a dynamically allocated
+ * string.
+ *
+ * \pre 
+ * - The calling client must have responsibility for the passed string.
+ * 
+ * \return
+ * none
+ *
+ * \post 
+ * - The string is no longer usable, any references to it must be discarded.
+ */
+void lub_string_free(
+	/**
+         * The string to be released
+         */
+			    char *string);
+
+/*
+ * These are the escape characters which are used by default when 
+ * expanding variables. These characters will be backslash escaped
+ * to prevent them from being interpreted in a script.
+ *
+ * This is a security feature to prevent users from arbitarily setting
+ * parameters to contain special sequences.
+ */
+extern const char *lub_string_esc_default;
+extern const char *lub_string_esc_regex;
+extern const char *lub_string_esc_quoted;
+
+/**
+ * This operation decode the escaped string.
+ *
+ * \pre
+ * - none
+ *
+ * \return
+ * - The allocated string without escapes.
+ *
+ * \post
+ * - The result string must be freed after using.
+ */
+char *lub_string_decode(const char *string);
+char *lub_string_ndecode(const char *string, unsigned int len);
+
+/**
+ * This operation encode the string using escape.
+ *
+ * \pre
+ * - none
+ *
+ * \return
+ * - The allocated string with escapes.
+ *
+ * \post
+ * - The result string must be freed after using.
+ */
+char *lub_string_encode(const char *string, const char *escape_chars);
+
+char *lub_string_tolower(const char *str);
+unsigned int lub_string_equal_part(const char *str1, const char *str2,
+	bool_t utf8);
+const char *lub_string_nextword(const char *string,
+	size_t *len, size_t *offset, size_t *quoted);
+unsigned int lub_string_wordcount(const char *line);
+
+_END_C_DECL
+#endif				/* _lub_string_h */
+/** @} */

+ 4 - 0
lub/string/module.am

@@ -0,0 +1,4 @@
+liblub_a_SOURCES += \
+	lub/string/string.c \
+	lub/string/private.h
+

+ 4 - 0
lub/string/private.h

@@ -0,0 +1,4 @@
+/*
+ * private.h
+ */
+#include "lub/string.h"

+ 340 - 0
lub/string/string.c

@@ -0,0 +1,340 @@
+/*
+ * string.c
+ */
+#include "private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lub/ctype.h"
+
+const char *lub_string_esc_default = "`|$<>&()#;\\\"!";
+const char *lub_string_esc_regex = "^$.*+[](){}";
+const char *lub_string_esc_quoted = "\\\"";
+
+/*--------------------------------------------------------- */
+void lub_string_free(char *ptr)
+{
+	free(ptr);
+}
+
+/*--------------------------------------------------------- */
+char *lub_string_ndecode(const char *string, unsigned int len)
+{
+	const char *s = string;
+	char *res, *p;
+	int esc = 0;
+
+	if (!string)
+		return NULL;
+
+	/* Allocate enough memory for result */
+	p = res = malloc(len + 1);
+
+	while (*s && (s < (string +len))) {
+		if (!esc) {
+			if ('\\' == *s)
+				esc = 1;
+			else
+				*p = *s;
+		} else {
+/*			switch (*s) {
+			case 'r':
+			case 'n':
+				*p = '\n';
+				break;
+			case 't':
+				*p = '\t';
+				break;
+			default:
+				*p = *s;
+				break;
+			}
+*/			*p = *s;
+			esc = 0;
+		}
+		if (!esc)
+			p++;
+		s++;
+	}
+	*p = '\0';
+
+	return res;
+}
+
+/*--------------------------------------------------------- */
+inline char *lub_string_decode(const char *string)
+{
+	return lub_string_ndecode(string, strlen(string));
+}
+
+/*----------------------------------------------------------- */
+/*
+ * This needs to escape any dangerous characters within the command line
+ * to prevent gaining access to the underlying system shell.
+ */
+char *lub_string_encode(const char *string, const char *escape_chars)
+{
+	char *result = NULL;
+	const char *p;
+
+	if (!escape_chars)
+		return lub_string_dup(string);
+	if (string && !(*string)) /* Empty string */
+		return lub_string_dup(string);
+
+	for (p = string; p && *p; p++) {
+		/* find any special characters and prefix them with '\' */
+		size_t len = strcspn(p, escape_chars);
+		lub_string_catn(&result, p, len);
+		p += len;
+		if (*p) {
+			lub_string_catn(&result, "\\", 1);
+			lub_string_catn(&result, p, 1);
+		} else {
+			break;
+		}
+	}
+	return result;
+}
+
+/*--------------------------------------------------------- */
+void lub_string_catn(char **string, const char *text, size_t len)
+{
+	if (text) {
+		char *q;
+		size_t length, initlen, textlen = strlen(text);
+
+		/* make sure the client cannot give us duff details */
+		len = (len < textlen) ? len : textlen;
+
+		/* remember the size of the original string */
+		initlen = *string ? strlen(*string) : 0;
+
+		/* account for '\0' */
+		length = initlen + len + 1;
+
+		/* allocate the memory for the result */
+		q = realloc(*string, length);
+		if (NULL != q) {
+			*string = q;
+			/* move to the end of the initial string */
+			q += initlen;
+
+			while (len--) {
+				*q++ = *text++;
+			}
+			*q = '\0';
+		}
+	}
+}
+
+/*--------------------------------------------------------- */
+void lub_string_cat(char **string, const char *text)
+{
+	size_t len = text ? strlen(text) : 0;
+	lub_string_catn(string, text, len);
+}
+
+/*--------------------------------------------------------- */
+char *lub_string_dup(const char *string)
+{
+	if (!string)
+		return NULL;
+	return strdup(string);
+}
+
+/*--------------------------------------------------------- */
+char *lub_string_dupn(const char *string, unsigned int len)
+{
+	char *res = NULL;
+
+	if (!string)
+		return res;
+	res = malloc(len + 1);
+	strncpy(res, string, len);
+	res[len] = '\0';
+
+	return res;
+}
+
+/*--------------------------------------------------------- */
+int lub_string_nocasecmp(const char *cs, const char *ct)
+{
+	int result = 0;
+	while ((0 == result) && *cs && *ct) {
+		/*lint -e155 Ignoring { }'ed sequence within an expression, 0 assumed 
+		 * MACRO implementation uses braces to prevent multiple increments
+		 * when called.
+		 */
+		int s = lub_ctype_tolower(*cs++);
+		int t = lub_ctype_tolower(*ct++);
+
+		result = s - t;
+	}
+	/*lint -e774 Boolean within 'if' always evealuates to True 
+	 * not the case because of tolower() evaluating to 0 under lint
+	 * (see above)
+	 */
+	if (0 == result) {
+		/* account for different string lengths */
+		result = *cs - *ct;
+	}
+	return result;
+}
+
+/*--------------------------------------------------------- */
+char *lub_string_tolower(const char *str)
+{
+	char *tmp = strdup(str);
+	char *p = tmp;
+
+	while (*p) {
+		*p = tolower(*p);
+		p++;
+	}
+
+	return tmp;
+}
+
+/*--------------------------------------------------------- */
+const char *lub_string_nocasestr(const char *cs, const char *ct)
+{
+	const char *p = NULL;
+	const char *result = NULL;
+
+	while (*cs) {
+		const char *q = cs;
+
+		p = ct;
+		/*lint -e155 Ignoring { }'ed sequence within an expression, 0 assumed 
+		 * MACRO implementation uses braces to prevent multiple increments
+		 * when called.
+		 */
+		/*lint -e506 Constant value Boolean
+		 * not the case because of tolower() evaluating to 0 under lint
+		 * (see above)
+		 */
+		while (*p && *q
+		       && (lub_ctype_tolower(*p) == lub_ctype_tolower(*q))) {
+			p++, q++;
+		}
+		if (0 == *p) {
+			break;
+		}
+		cs++;
+	}
+	if (p && !*p) {
+		/* we've found the first match of ct within cs */
+		result = cs;
+	}
+	return result;
+}
+
+/*--------------------------------------------------------- */
+unsigned int lub_string_equal_part(const char *str1, const char *str2,
+	bool_t utf8)
+{
+	unsigned int cnt = 0;
+
+	if (!str1 || !str2)
+		return cnt;
+	while (*str1 && *str2) {
+		if (*str1 != *str2)
+			break;
+		cnt++;
+		str1++;
+		str2++;
+	}
+	if (!utf8)
+		return cnt;
+
+	/* UTF8 features */
+	if (cnt && (UTF8_11 == (*(str1 - 1) & UTF8_MASK)))
+		cnt--;
+
+	return cnt;
+}
+
+/*--------------------------------------------------------- */
+const char *lub_string_suffix(const char *string)
+{
+	const char *p1, *p2;
+	p1 = p2 = string;
+	while (*p1) {
+		if (lub_ctype_isspace(*p1)) {
+			p2 = p1;
+			p2++;
+		}
+		p1++;
+	}
+	return p2;
+}
+
+/*--------------------------------------------------------- */
+const char *lub_string_nextword(const char *string,
+	size_t *len, size_t *offset, size_t *quoted)
+{
+	const char *word;
+
+	*quoted = 0;
+
+	/* Find the start of a word (not including an opening quote) */
+	while (*string && isspace(*string)) {
+		string++;
+		(*offset)++;
+	}
+	/* Is this the start of a quoted string ? */
+	if (*string == '"') {
+		*quoted = 1;
+		string++;
+	}
+	word = string;
+	*len = 0;
+
+	/* Find the end of the word */
+	while (*string) {
+		if (*string == '\\') {
+			string++;
+			(*len)++;
+			if (*string) {
+				(*len)++;
+				string++;
+			}
+			continue;
+		}
+		/* End of word */
+		if (!*quoted && isspace(*string))
+			break;
+		if (*string == '"') {
+			/* End of a quoted string */
+			*quoted = 2;
+			break;
+		}
+		(*len)++;
+		string++;
+	}
+
+	return word;
+}
+
+/*--------------------------------------------------------- */
+unsigned int lub_string_wordcount(const char *line)
+{
+	const char *word;
+	unsigned int result = 0;
+	size_t len = 0, offset = 0;
+	size_t quoted;
+
+	for (word = lub_string_nextword(line, &len, &offset, &quoted);
+		*word || quoted;
+		word = lub_string_nextword(word + len, &len, &offset, &quoted)) {
+		/* account for the terminating quotation mark */
+		len += quoted ? quoted - 1 : 0;
+		result++;
+	}
+
+	return result;
+}
+
+/*--------------------------------------------------------- */

+ 24 - 0
lub/types.h

@@ -0,0 +1,24 @@
+/*
+ * types.h
+ */
+/**
+\ingroup  lub
+\defgroup lub_types types
+
+\brief This provides some primative types not found in ANSI-C.
+@{
+*/
+
+#ifndef _lub_types_h
+#define _lub_types_h
+
+/**
+ * A boolean type for ANSI-C
+ */
+typedef enum {
+	BOOL_FALSE,
+	BOOL_TRUE
+} bool_t;
+
+/** @} */
+#endif				/* _lub_types_h */