/* String Manipulations Standard: int strlinelen(char *s) int strlongestline(char *s) int strlines(char *s) int strpfx(char *str, char *pfx) int strcasepfx(char *str, char *pfx) void strtoupper(char *s) void strtolower(char *s) void substr(char *s, char *token, char *val) char *StringCopyAlloc(char *str) void *MemoryCopyAlloc(void *ptr, int nbytes) void StringStripSpaces(char *s) char **StringQSort(char **strings, int nitems) char *StringTailSpaces(char *string, int len) void StringShortenFL(char *string, int limit) void StringFreeArray(char **strv, int strc) Configuration files: int StringIsYes(char *string) int StringIsComment(char *s, char c) char *StringCfgParseParm(char *string) char *StringCfgParseValue(char *string) Other Parsing: int StringParseStdColor( char *string, u_int8_t *r_rtn, u_int8_t *g_rtn, u_int8_t *b_rtn ) int StringParseIP( char *string, u_int8_t *c1, u_int8_t *c2, u_int8_t *c3, u_int8_t *c4 ) CyberSpace: int StringGetNetCommand(char *str) char *StringGetNetArgument(char *str) Time: char *StringCurrentTimeFormat(char *format) char *StringTimeFormat(char *format, time_t seconds) char *StringFormatTimePeriod(time_t seconds) */ #include #include #include #include #include #include extern char *tzname[2]; #include #include #include "../include/os.h" #include "../include/cfgfmt.h" #include "../include/cs.h" #include "../include/string.h" /* Sort function used by StringQSort(). */ int SORT(const void *a, const void *b); /* * Returns the length in bytes, of the line s. * The end point character must be either a '\n', '\r', or * '\0'. */ int strlinelen(char *s) { int i = 0; if(s == NULL) return(0); while((*s != '\0') && (*s != '\n') && (*s != '\r') ) { i++; s++; } return(i); } /* * Returns the length of the longest line in string s. */ int strlongestline(char *s) { int n; int longest = 0; if(s == NULL) return(longest); while(1) { n = strlinelen(s); if(n > longest) longest = n; s += n; if(*s == '\0') break; s++; } return(longest); } /* * Returns the number of '\r' or '\n' characters + 1 * in string s. * * If the first character is '\0' in string s or string s * is NULL, then 0 will be returned. */ int strlines(char *s) { int lines = 0; if(s == NULL) return(lines); if(*s == '\0') return(lines); /* Must increment first line. */ lines++; while(*s != '\0') { if((*s == '\r') || (*s == '\n') ) lines++; s++; } return(lines); } /* * Returns 1 if pfx is a prefix of str. * * Returns 0 if pfx is not a prefix of str or if an error * occured. */ int strpfx(char *str, char *pfx) { /* If either strings is NULL, return false. */ if((str == NULL) || (pfx == NULL) ) return(0); /* If pfx contains no characters, return false. */ if(*pfx == '\0') return(0); /* Begin prefix matching. */ while(*pfx != '\0') { if(*str != *pfx) return(0); str++, pfx++; } return(1); } int strcasepfx(char *str, char *pfx) { /* If either strings is NULL, return false. */ if((str == NULL) || (pfx == NULL) ) return(0); /* If pfx contains no characters, return false. */ if(*pfx == '\0') return(0); /* Begin prefix matching. */ while(*pfx != '\0') { if(toupper(*str) != toupper(*pfx)) return(0); str++, pfx++; } return(1); } /* * Sets all characters in string s to upper. */ void strtoupper(char *s) { if(s == NULL) return; while(*s != '\0') *s++ = toupper(*s); return; } void strtolower(char *s) { if(s == NULL) return; while(*s != '\0') *s++ = tolower(*s); return; } /* * Substitutes all occurances of string token in string s * with string val. String s must have enough capacity for * all substitutions. * * Example: substr("Hi there %name!", "%name", "Kattie") * Turns into: "Hi there Kattie!" */ void substr(char *s, char *token, char *val) { int i, tl, vl; char *strptr1, *strptr2, *strptr3, *strptr4; if((s == NULL) || (token == NULL) ) return; if(val == NULL) val = ""; /* Token string must not be empty. */ if(*token == '\0') return; /* Token and value strings may not have the same content. */ if(!strcmp(val, token)) return; /* Get lengths of token and value strings. */ tl = strlen(token); vl = strlen(val); /* Set strptr1 to begining of string s. */ strptr1 = s; /* Begin substituting. */ while(1) { /* Seek next instance of token string. */ strptr1 = strstr(strptr1, token); if(strptr1 == NULL) break; /* Calculate end pointer of strptr1. */ i = strlen(strptr1); strptr2 = strptr1 + i; if(tl > vl) { /* Token string is longer than value string. */ /* Calculate starting pointer positions. */ strptr3 = strptr1 + vl; strptr4 = strptr1 + tl; /* Shift tailing portion of string. */ while(strptr4 <= strptr2) *strptr3++ = *strptr4++; } else if(tl < vl) { /* Token string is less than value string. */ /* Calculate starting pointer positions. */ strptr3 = strptr2; strptr4 = strptr2 + vl - tl; /* Shift tailing portion of string. */ while(strptr3 > strptr1) *strptr4-- = *strptr3--; } memcpy(strptr1, val, vl); } return; } /* * Returns an allocated string which is a copy of the given * string str. Can return NULL on error. */ char *StringCopyAlloc(char *str) { int len; char *strptr = NULL; if(str == NULL) return(strptr); len = strlen(str); if(len < 0) len = 0; strptr = (char *)malloc((len + 1) * sizeof(char)); if(strptr != NULL) { strncpy(strptr, str, len); strptr[len] = '\0'; } return(strptr); } /* * Allocates a new segment of memory of length specified by * nbytes with identical content as specified by ptr. * * The given ptr must be atleast nbytes long. */ void *MemoryCopyAlloc(void *ptr, int nbytes) { void *ptr2 = NULL; if(nbytes < 1) return(ptr2); ptr2 = malloc(nbytes); if(ptr2 != NULL) { if(ptr == NULL) memset(ptr2, 0x00, nbytes); else memcpy(ptr2, ptr, nbytes); } return(ptr2); } /* * Strips blank characters leading and tailing string s. */ void StringStripSpaces(char *s) { int tar, src, lead, tail; /* Error checks. */ if(s == NULL) return; if(*s == '\0') return; /* Strip leading blank characters. */ lead = 0; while(isblank(s[lead])) lead++; if(lead > 0) { for(tar = 0, src = lead; s[src] != '\0'; tar++, src++) s[tar] = s[src]; s[tar] = '\0'; /* Calculate tail position. */ tail = (tar > 0) ? tar - 1 : 0; } else { /* Calculate tail position. */ tar = strlen(s); tail = (tar > 0) ? tar - 1 : 0; } /* Strip tailing blank characters. */ for(tar = tail; tar >= 0; tar--) { if(isblank(s[tar])) s[tar] = '\0'; else break; } return; } /* * Sorts given string array strings using the qsort() methoid. * Returns NULL on error and strings on success. */ /* For sorting. */ int SORT(const void *a, const void *b) { char *x, *y; x = *((char **)a); y = *((char **)b); return(strcmp(x, y)); } char **StringQSort(char **strings, int nitems) { if(strings == NULL) return(NULL); if(nitems <= 0) return(NULL); qsort(strings, nitems, sizeof(char *), SORT); return(strings); } char *StringTailSpaces(char *string, int len) { int x; int prev_len; /* Error checks. */ if(string == NULL) return(NULL); /* Length of string must have len + 1 for NULL terminating byte. */ string[len] = '\0'; prev_len = strlen(string); for(x = prev_len; x < len; x++) { string[x] = ' '; } return(string); } /* * Shortens string to number of characters limit. * If the limit is > 3 then three '.' characters are prepended. * * If length of string is <= to limit, then nothing is done, * example (using 10 as the limit): * * "Hello there kitty!" becomes "... kitty!" */ void StringShortenFL(char *string, int limit) { int ol; char *strptr1, *strptr2; if(string == NULL) return; if(limit < 0) { if(*string != '\0') *string = '\0'; return; } ol = strlen(string); if(ol > limit) { strptr1 = string; strptr2 = &string[ol - limit]; while(*strptr2 != '\0') *strptr1++ = *strptr2++; if(limit >= 3) { strptr1 = string; strptr2 = &string[3]; while(strptr1 < strptr2) *strptr1++ = '.'; } string[limit] = '\0'; } return; } /* * Frees an array of strings. strc indicates the number of * allocated strings in the array pointer strv. * * If strv is NULL and/or strc is <= 0 then nothing will be * done. */ void StringFreeArray(char **strv, int strc) { int i; if(strv == NULL) return; /* Free each string in array. */ for(i = 0; i < strc; i++) free(strv[i]); /* Free array pointers. */ free(strv); return; } /* * Checks if the string is a "yes" (and standard variations * accepted and checked as well). */ int StringIsYes(char *string) { if(string == NULL) return(0); /* Skip leading spaces. */ while(isblank(*string)) string++; /* Is first char a number from 0 to 9 (for "0" or "1")? */ if(isdigit(*string)) { if(string[0] != '0') return(1); else return(0); } /* Is first char a 'o' (for "on" or "off")? */ else if(toupper(*string) == 'O') { /* Check second char, is it an 'n'? */ if(toupper(string[1]) == 'N') return(1); else return(0); } /* Else check first char for "yes" or "no". */ else { if(toupper(*string) == 'Y') return(1); else return(0); } return(0); } /* * Returns true if string is a comment in accordance with * the UNIX configuration file format. * * The comment character c should be * (but does not have to be) UNIXCFG_COMMENT_CHAR. */ int StringIsComment(char *s, char c) { /* Is string NULL? */ if(s == NULL) return(0); /* Skip leading spaces. */ while(isblank(*s)) s++; if(*s == c) return(1); else return(0); } /* * Returns the parameter section of string which should comform to * the standard configuration format of "=" as * a statically allocated string or NULL on error. */ char *StringCfgParseParm(char *string) { int x, y; int got_parm_start; static char parameter[CFG_PARAMETER_MAX]; /* Is string empty? */ if(string == NULL) return(NULL); if((string[0] == '\0') || (string[0] == '\r') || (string[0] == '\n') ) return(NULL); /* Is string a comment? */ if(StringIsComment(string, UNIXCFG_COMMENT_CHAR)) return(NULL); /* Begin fetching parameter from string. */ got_parm_start = 0; for(x = 0, y = 0; (x < CFG_STRING_MAX) && (y < CFG_PARAMETER_MAX); x++ ) { /* Skip newline escape sequences. */ if((string[x] == '\\') && ((x + 1) < CFG_STRING_MAX) ) { if((string[x + 1] == '\n') || (string[x + 1] == '\r')) { x++; continue; } } /* Skip other escape sequences. */ if(string[x] == '\\') { x++; if(x >= CFG_STRING_MAX) break; } /* End on NULL, new line, or delimiter. */ if((string[x] == '\0') || (string[x] == '\r') || (string[x] == '\n') || (string[x] == CFG_PARAMETER_DELIMITER) ) { parameter[y] = '\0'; break; } if(got_parm_start == 0) { if((string[x] == ' ') || (string[x] == '\t') ) continue; else got_parm_start = 1; } parameter[y] = string[x]; y++; } /* Null terminate parameter. */ parameter[CFG_PARAMETER_MAX - 1] = '\0'; StringStripSpaces(parameter); return(parameter); } /* * Returns the value section of string which should comform to * the standard configuration format of "=". * * The returned string will never be NULL and will be striped of * tailing or leading spaces. */ char *StringCfgParseValue(char *string) { int x, y, got_value; static char value[CFG_VALUE_MAX]; /* Is string empty? */ if(string == NULL) return(NULL); if((string[0] == '\0') || (string[0] == '\r') || (string[0] == '\n') ) return(NULL); /* Is string a comment? */ if(StringIsComment(string, UNIXCFG_COMMENT_CHAR)) return(NULL); /* Does string have a delimiter? */ if(strchr(string, CFG_PARAMETER_DELIMITER) == NULL) return(NULL); /* Begin fetching value from string. */ got_value = 0; for(x = 0, y = 0; (x < CFG_STRING_MAX) && (y < CFG_VALUE_MAX); x++ ) { /* Skip newline escape sequences. */ if((string[x] == '\\') && ((x + 1) < CFG_STRING_MAX) ) { if((string[x + 1] == '\n') || (string[x + 1] == '\r')) { x++; continue; } } /* Skip other escape sequences. */ if(string[x] == '\\') { x++; if(x >= CFG_STRING_MAX) break; } /* Stop on newline or NULL. */ if((string[x] == '\0') || (string[x] == '\r') || (string[x] == '\n') ) { value[y] = '\0'; break; } if(got_value == 0) { if(string[x] == CFG_PARAMETER_DELIMITER) { got_value = 1; continue; } else { continue; } } value[y] = string[x]; y++; } /* Null terminate value. */ value[CFG_VALUE_MAX - 1] = '\0'; StringStripSpaces(value); return(value); } /* *********************************************************************** * * Other Parsing */ /* * Parses a standard color string "#rrggbb" where rr, gg, * and bb are in hexidecimal notation. * * Returns 0 on success, -1 on general error, and * -2 for incomplete or ambiguous. */ int StringParseStdColor( char *s, u_int8_t *r_rtn, u_int8_t *g_rtn, u_int8_t *b_rtn ) { int i; int r = 0; int g = 0; int b = 0; if(s == NULL) return(-1); /* Red. */ while((*s == '#') || isblank(*s)) s++; if(!*s) return(-2); i = 0; while(isxdigit(*s) && (i < 2)) { if(isdigit(*s)) r = (r << 4) + (*s - '0'); else r = (r << 4) + (tolower(*s) - 'a' + 10); i++; s++; } if(r_rtn != NULL) *r_rtn = (u_int8_t)r; /* Green. */ i = 0; while(isxdigit(*s) && (i < 2)) { if(isdigit(*s)) g = (g << 4) + (*s - '0'); else g = (g << 4) + (tolower(*s) - 'a' + 10); i++; s++; } if(g_rtn != NULL) *g_rtn = (u_int8_t)g; /* Blue. */ i = 0; while(isxdigit(*s) && (i < 2)) { if(isdigit(*s)) b = (b << 4) + (*s - '0'); else b = (b << 4) + (tolower(*s) - 'a' + 10); i++; s++; } if(b_rtn != NULL) *b_rtn = (u_int8_t)b; return(0); } /* * Parse IP address. * * Returns 0 on success, -1 on general error, and * -2 for incomplete or ambiguous. */ int StringParseIP( char *s, u_int8_t *c1, u_int8_t *c2, u_int8_t *c3, u_int8_t *c4 ) { char *strptr; char ls[4]; if(s == NULL) return(-1); while(isblank(*s)) s++; if(*s == '\0') return(-2); /* First number. */ if(c1 != NULL) { strncpy(ls, s, 4); ls[3] = '\0'; strptr = strchr(ls, '.'); if(strptr != NULL) *strptr = '\0'; *c1 = (u_int8_t)atoi(ls); } strptr = strchr(s, '.'); if(strptr == NULL) return(-2); s = strptr + 1; /* Second number. */ if(c2 != NULL) { strncpy(ls, s, 4); ls[3] = '\0'; strptr = strchr(ls, '.'); if(strptr != NULL) *strptr = '\0'; *c2 = (u_int8_t)atoi(ls); } strptr = strchr(s, '.'); if(strptr == NULL) return(-2); s = strptr + 1; /* Third number. */ if(c3 != NULL) { strncpy(ls, s, 4); ls[3] = '\0'; strptr = strchr(ls, '.'); if(strptr != NULL) *strptr = '\0'; *c3 = (u_int8_t)atoi(ls); } strptr = strchr(s, '.'); if(strptr == NULL) return(-2); s = strptr + 1; /* Fourth number. */ if(c4 != NULL) { strncpy(ls, s, 4); ls[3] = '\0'; strptr = strchr(ls, ' '); /* Last, look for a space. */ if(strptr != NULL) *strptr = '\0'; *c4 = (u_int8_t)atoi(ls); } return(0); } /* ****************************************************************** * * CyberSpace */ int StringGetNetCommand(char *str) { char *strptr; static char cmd_str[CS_DATA_MAX_LEN]; if(str == NULL) return(-1); strncpy(cmd_str, str, CS_DATA_MAX_LEN); cmd_str[CS_DATA_MAX_LEN - 1] = '\0'; /* Get command. */ strptr = strchr(cmd_str, ' '); if(strptr != NULL) *strptr = '\0'; return(atoi(cmd_str)); } /* * Returns the argument from str with spaces stripped. * This function never returns NULL. */ char *StringGetNetArgument(char *str) { char *strptr; static char arg[CS_DATA_MAX_LEN]; if(str == NULL) return(""); strncpy(arg, str, CS_DATA_MAX_LEN); arg[CS_DATA_MAX_LEN - 1] = '\0'; /* Get argument. */ strptr = strchr(arg, ' '); if(strptr != NULL) { strptr += 1; StringStripSpaces(strptr); return(strptr); } return(""); } /* ********************************************************************** * * Time Formatting * */ #ifndef MAX_TIME_STR # define MAX_TIME_STR 256 #endif /* * Returns a formatted time string in accordance with given format * format and returns the statically allocated string. * * This function will never return NULL. */ char *StringCurrentTimeFormat(char *format) { size_t len; time_t current; struct tm *tm_ptr; static char s[MAX_TIME_STR]; if(format == NULL) return(""); if(*format == '\0') return(""); /* Get current time. */ time(¤t); tm_ptr = localtime(¤t); if(tm_ptr == NULL) return(""); /* Format time string. */ len = strftime( s, MAX_TIME_STR, format, tm_ptr ); if(len >= MAX_TIME_STR) len = MAX_TIME_STR - 1; if(len < 0) len = 0; /* Null terminate. */ s[len] = '\0'; return(s); } /* * Returns statically allocated string containing formatted * values. */ char *StringTimeFormat(char *format, time_t seconds) { size_t len; struct tm *tm_ptr; static char s[MAX_TIME_STR]; if(format == NULL) return(""); if(*format == '\0') return(""); tm_ptr = localtime(&seconds); if(tm_ptr == NULL) return(""); /* Format time string. */ len = strftime( s, MAX_TIME_STR, format, tm_ptr ); if(len >= MAX_TIME_STR) len = MAX_TIME_STR - 1; if(len < 0) len = 0; /* Null terminate. */ s[len] = '\0'; return(s); } /* * Returns a statically allocated string containing a verbose * statement of the delta time seconds. */ char *StringFormatTimePeriod(time_t seconds) { static char s[MAX_TIME_STR]; /* Reset. */ *s = '\0'; if(seconds < 60) { sprintf(s, "%ld sec%s", seconds, ((seconds > 1) ? "s" : "") ); } else if(seconds < 3600) { seconds = seconds / 60; sprintf(s, "%ld min%s", seconds, ((seconds > 1) ? "s" : "") ); } else if(seconds < 86400) { seconds = seconds / 3600; sprintf(s, "%ld hour%s", seconds, ((seconds > 1) ? "s" : "") ); } else { seconds = seconds / 86400; sprintf(s, "%ld day%s", seconds, ((seconds > 1) ? "s" : "") ); } /* Null terminate just in case. */ s[MAX_TIME_STR - 1] = '\0'; return(s); }