/*___INFO__MARK_BEGIN__*/ /************************************************************************* * * The Contents of this file are made available subject to the terms of * the Sun Industry Standards Source License Version 1.2 * * Sun Microsystems Inc., March, 2001 * * * Sun Industry Standards Source License Version 1.2 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.2 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2001 by Sun Microsystems, Inc. * * All Rights Reserved. * ************************************************************************/ /*___INFO__MARK_END__*/ #include #include #include #include #include #include #include "sgermon.h" #include "sge_stdlib.h" #include "sge_string.h" #include "sge_log.h" #include "msg_utilib.h" #define IS_DELIMITOR(c,delimitor) \ (delimitor?(strchr(delimitor, c)?1:0):isspace(c)) /****** uti/string/sge_basename() ********************************************* * NAME * sge_basename() -- get basename for path * * SYNOPSIS * char* sge_basename(const char *name, int delim) * * FUNCTION * Determines the basename for a path like string - the last field * of a string where fields are separated by a fixed one character * delimiter. * * INPUTS * const char *name - contains the input string (path) * int delim - delimiter * * RESULT * char* - pointer to base of name after the last delimter * NULL if "name" is NULL or zero length string or * delimiter is the last character in "name" * * EXAMPLE * sge_basename("/usr/local/bin/flex", '/'); returns "flex" * * NOTES * MT-NOTE: sge_basename() is MT safe ******************************************************************************/ const char *sge_basename(const char *name, int delim) { char *cp; DENTER(BASIS_LAYER, "sge_basename"); if (!name) { DRETURN(NULL); } if (name[0] == '\0') { DRETURN(NULL); } cp = strrchr(name, delim); if (!cp) { DRETURN(name); } else { cp++; if (*cp == '\0') { DRETURN(NULL); } else { DRETURN(cp); } } } /****** uti/string/sge_jobname() *********************************************** * NAME * sge_jobname() -- get jobname of command line string * * SYNOPSIS * const char* sge_jobname(const char *name) * * FUNCTION * Determine the jobname of a command line. The following definition is used * for the jobname: * - take everything up to the first semicolon * - take everything up to the first whitespace * - take the basename * * INPUTS * const char *name - contains the input string (command line) * * RESULT * const char* - pointer to the jobname * NULL if name is NULL or only '\0' * * EXAMPLE * Command line jobname * ---------------------------------------------- * "cd /home/me/5five; hostname" --> cd * "/home/me/4Ujob" --> 4Ujob (invalid, will be denied) * "cat /tmp/5five" --> cat * "bla;blub" --> bla * "a b" --> a * * * NOTES * MT-NOTE: sge_jobname() is not MT safe * * SEE ALSO * sge_basename() *******************************************************************************/ const char *sge_jobname(const char *name) { const char *cp = NULL; DENTER(BASIS_LAYER, "sge_jobname"); if (name && name[0] != '\0' ) { cp = sge_strtok(name, ";"); cp = sge_strtok(cp, " "); cp = sge_basename(cp, '/'); } DRETURN(cp); } /****** uti/string/sge_dirname() ********************************************** * NAME * sge_dirname() -- Return first part of string up to deliminator * * SYNOPSIS * char* sge_dirname(const char *name, int delim) * * FUNCTION * The function will return a malloced string containing the first * part of 'name' up to, but not including deliminator. NULL will * be returned if 'name' is NULL or a zero length string or if * 'delim' is the first character in 'name' * * INPUTS * const char *name - string * int delim - deliminator * * RESULT * char* - malloced string * * NOTES * This routine is called "dirname" in opposite to "basename" * but is mostly used to strip off the domainname of a FQDN * MT-NOTE: sge_dirname() is MT safe ******************************************************************************/ char *sge_dirname(const char *name, int delim) { char *cp, *cp2; DENTER(BASIS_LAYER, "sge_dirname"); if (!name) { DRETURN(NULL); } if (name[0] == '\0' || name[0] == delim) { DRETURN(NULL); } cp = strchr(name, delim); if (!cp) { /* no occurence of delim */ cp2 = strdup(name); DRETURN(cp2); } else { if ((cp2 = malloc((cp - name) + 1)) == NULL) { DRETURN(NULL); } else { strncpy(cp2, name, cp - name); cp2[cp - name] = '\0'; DRETURN(cp2); } } } /****** uti/string/sge_strtok() *********************************************** * NAME * sge_strtok() -- Replacement for strtok() * * SYNOPSIS * char* sge_strtok(const char *str, const char *delimitor) * * FUNCTION * Replacement for strtok(). If no delimitor is given * isspace() is used. * * INPUTS * const char *str - string which should be tokenized * const char *delimitor - delimitor string * * RESULT * char* - first/next token of str. * * NOTES * MT-NOTE: sge_strtok() is not MT safe, use sge_strtok_r() instead * * SEE ALSO * uti/string/sge_strtok_r() ******************************************************************************/ char *sge_strtok(const char *str, const char *delimitor) { char *cp; char *saved_cp; static char *static_cp = NULL; static char *static_str = NULL; static unsigned int alloc_len = 0; unsigned int n; bool done; DENTER(BASIS_LAYER, "sge_strtok"); if (str) { n = strlen(str); if (static_str) { if (n > alloc_len) { /* need more memory */ free(static_str); static_str = malloc(n + 1); alloc_len = n; } } else { static_str = malloc(n + 1); alloc_len = n; } strcpy(static_str, str); saved_cp = static_str; } else { saved_cp = static_cp; } /* seek first character which is no '\0' and no delimitor */ done = false; while (!done) { /* found end of string */ if (saved_cp == NULL || *saved_cp == '\0') { DRETURN(NULL); } /* eat white spaces */ if (!IS_DELIMITOR((int) saved_cp[0], delimitor)) { done = true; break; } saved_cp++; } /* seek end of string given by '\0' or delimitor */ cp = saved_cp; done = false; while (!done) { if (!cp[0]) { static_cp = cp; DRETURN(saved_cp); } /* test if we found a delimitor */ if (IS_DELIMITOR((int) cp[0], delimitor)) { cp[0] = '\0'; cp++; static_cp = cp; DRETURN(saved_cp); } cp++; } DRETURN(NULL); } /****** uti/string/sge_strlcpy() *********************************************** * NAME * sge_strlcpy() -- sge strlcpy implementation * * SYNOPSIS * size_t sge_strlcpy(char *dst, const char *src, size_t dstsize) * * FUNCTION * copies "dstsize"-1 characters from from "src" to "dst" and terminates * the src string with '\0'- Returns the size of the "src" string. * * INPUTS * char *dst - destination * const char *src - source string (must be '\0' terminated) * size_t dstsize - size of source string * * RESULT * size_t - strlen of src, not dst !!! * * NOTES * MT-NOTE: sge_strlcpy() is MT safe *******************************************************************************/ size_t sge_strlcpy(char *dst, const char *src, size_t dstsize) { size_t index = 0; if (dst == NULL) { return 0; } if (src == NULL) { dst[0] = '\0'; return 0; } for (index = 0; (src[index] != '\0') && (index < dstsize - 1); index++) { dst[index] = src[index]; } dst[index] = '\0'; while ( src[index] != '\0') { index++; } return index; } /****** uti/string/sge_strtok_r() ********************************************* * NAME * sge_strtok_r() -- Reentrant version of strtok() * * SYNOPSIS * char* sge_strtok_r(const char *str, const char *delimitor, * struct saved_vars_s **context) * * FUNCTION * Reentrant version of sge_strtok. When 'str' is not NULL, * '*context'has to be NULL. If 'str' is NULL, '*context' * must not be NULL. The caller is responsible for freeing * '*context' with sge_free_saved_vars(). * If no delimitor is given isspace() is used. * * INPUTS * const char *str - str which should be tokenized * const char *delimitor - delimitor string * struct saved_vars_s **context - context * * RESULT * char* - first/next token * * SEE ALSO * uti/string/sge_strtok() * uti/string/sge_free_saved_vars() * * NOTES * MT-NOTE: sge_strtok_r() is MT safe ******************************************************************************/ char *sge_strtok_r(const char *str, const char *delimitor, struct saved_vars_s **context) { char *cp; char *saved_cp; struct saved_vars_s *saved; bool done; DENTER(BASIS_LAYER, "sge_strtok_r"); if (str != NULL) { if (*context != NULL) { ERROR((SGE_EVENT, MSG_POINTER_INVALIDSTRTOKCALL)); } *context = (struct saved_vars_s *)malloc(sizeof(struct saved_vars_s)); memset(*context, 0, sizeof(struct saved_vars_s)); saved = *context; saved->static_str = malloc(strlen(str) + 1); strcpy(saved->static_str, str); saved_cp = saved->static_str; } else { if (*context == NULL) { ERROR((SGE_EVENT, MSG_POINTER_INVALIDSTRTOKCALL1)); DRETURN(NULL); } saved = *context; saved_cp = saved->static_cp; } /* seek first character which is no '\0' and no delimitor */ done = false; while (!done) { /* found end of string */ if (saved_cp == NULL || *saved_cp == '\0') { DRETURN(NULL); } /* eat white spaces */ if (!IS_DELIMITOR((int) saved_cp[0], delimitor)) { done = true; break; } saved_cp++; } /* seek end of string given by '\0' or delimitor */ cp = saved_cp; done = false; while (!done) { if (!cp[0]) { saved->static_cp = cp; DRETURN(saved_cp); } /* test if we found a delimitor */ if (IS_DELIMITOR((int) cp[0], delimitor)) { cp[0] = '\0'; cp++; saved->static_cp = cp; DRETURN(saved_cp); } cp++; } DRETURN(NULL); } /****** uti/string/sge_free_saved_vars() ************************************** * NAME * sge_free_saved_vars() -- Free 'context' of sge_strtok_r() * * SYNOPSIS * void sge_free_saved_vars(struct saved_vars_s *context) * * FUNCTION * Free 'context' of sge_strtok_r() * * INPUTS * struct saved_vars_s *context * * SEE ALSO * uti/string/sge_strtok_r() * * NOTES * MT-NOTE: sge_free_saved_vars() is MT safe ******************************************************************************/ void sge_free_saved_vars(struct saved_vars_s *context) { if (context) { if (context->static_str) { free(context->static_str); } free(context); } } /****** uti/string/sge_strdup() *********************************************** * NAME * sge_strdup() -- Replacement for strdup() * * SYNOPSIS * char* sge_strdup(char *old, const char *s) * * FUNCTION * Duplicate string 's'. "Use" 'old' buffer. * * INPUTS * char *old - buffer (will be freed) * const char *s - string * * RESULT * char* - malloced string * * NOTES * MT-NOTE: sge_strdup() is MT safe ******************************************************************************/ char *sge_strdup(char *old, const char *s) { char *ret = NULL; /* * target (old) and source (s) might point to the same object! * therefore free old only after the dup */ if (s != NULL) { int n = strlen(s); ret = malloc(n + 1); if (ret != NULL) { strcpy(ret, s); } } /* free and NULL the old pointer */ FREE(old); return ret; } /****** uti/string/sge_strip_blanks() ***************************************** * NAME * sge_strip_blanks() -- Strip blanks from string * * SYNOPSIS * void sge_strip_blanks(char *str) * * FUNCTION * Strip all blanks contained in a string. The string is used * both as source and drain for the necessary copy operations. * The string is '\0' terminated afterwards. * * INPUTS * char *str - pointer to string to be condensed * * NOTES * MT-NOTE: sge_strip_blanks() is MT safe ******************************************************************************/ void sge_strip_blanks(char *str) { char *cp = str; DENTER(BASIS_LAYER, "sge_strip_blanks"); if (!str) { DRETURN_VOID; } while (*str) { if (*str != ' ') { if (cp != str) *cp = *str; cp++; } str++; }; *cp = '\0'; DRETURN_VOID; } /****** uti/string/sge_strip_white_space_at_eol() ****************************** * NAME * sge_strip_white_space_at_eol() -- truncate white space at EOL * * SYNOPSIS * void sge_strip_white_space_at_eol(char *str) * * FUNCTION * Truncate white space from the end of the string * * INPUTS * char *str - string to be modified * * RESULT * void - NONE * * NOTES * MT-NOTE: sge_strip_white_space_at_eol() is MT safe *******************************************************************************/ void sge_strip_white_space_at_eol(char *str) { DENTER(BASIS_LAYER, "sge_strip_white_space_at_eol"); if (str != NULL) { size_t length = strlen(str); while (str[length - 1] == ' ' || str[length - 1] == '\t') { str[length - 1] = '\0'; length--; } } DRETURN_VOID; } /****** uti/string/sge_strip_slash_at_eol() ****************************** * NAME * sge_strip_slash_at_eol() -- truncate slash at EOL * * SYNOPSIS * void sge_strip_slash_at_eol(char *str) * * FUNCTION * Truncate slash from the end of the string * * INPUTS * char *str - string to be modified * * RESULT * void - NONE * * NOTES * MT-NOTE: sge_strip_slash_at_eol() is MT safe *******************************************************************************/ void sge_strip_slash_at_eol(char *str) { DENTER(BASIS_LAYER, "sge_strip_slash_at_eol"); if (str != NULL) { size_t length = strlen(str); while (str[length - 1] == '/') { str[length - 1] = '\0'; length--; } } DRETURN_VOID; } /****** uti/string/sge_delim_str() ******************************************* * NAME * sge_delim_str() -- Trunc. a str according to a delimiter set * * SYNOPSIS * char* sge_delim_str(char *str, char **delim_pos, * const char *delim) * * FUNCTION * Truncates a string according to a delimiter set. A copy of * the string truncated according to the delimiter set will be * returned. * * ATTENTION: The user is responsible for freeing the allocated * memory outside this routine. If not enough space could be * allocated, NULL is returned. * * INPUTS * char *str - string to be truncated * char **delim_pos - A placeholder for the delimiting position * in str on exit. * If set on entry the position of the * delimiter in the input string 'str' is * returned. If no delimiting character in * string was found, the address of the * closing '\0' in 'str' is returned. * const char *delim - string containing delimiter characters * * RESULT * char* - Truncated copy of 'str' (Has to be freed by the caller!) * * NOTES * MT-NOTE: sge_delim_str() is MT safe ******************************************************************************/ char *sge_delim_str(char *str, char **delim_pos, const char *delim) { char *cp = NULL; char *tstr = NULL; DENTER(BASIS_LAYER, "sge_delim_str"); /* we want it non-destructive --> we need a copy of str */ if ((tstr = strdup(str)) == NULL) { DRETURN(NULL); } /* walk through str to find a character contained in delim or a * closing \0 */ cp = tstr; while (*cp) { if (strchr(delim, (int) *cp)) /* found */ break; cp++; } /* cp now either points to a closing \0 or to a delim character */ if (*cp) { /* if it points to a delim character */ *cp = '\0'; /* terminate str with a \0 */ } if (delim_pos) { /* give back delimiting position for name */ *delim_pos = str + strlen(tstr); } /* delim_pos either points to the delimiter or the closing \0 in str */ DRETURN(tstr); } /****** uti/string/sge_strnullcmp() ******************************************* * NAME * sge_strnullcmp() -- Like strcmp() but honours NULL ptrs. * * SYNOPSIS * int sge_strnullcmp(const char *a, const char *b) * * FUNCTION * Like strcmp() apart from the handling of NULL strings. * These are treated as being less than any not-NULL strings. * Important for sorting lists where NULL strings can occur. * * INPUTS * const char *a - 1st string * const char *b - 2nd string * * RESULT * int - result * 0 - strings are the same or both NULL * -1 - a < b or a is NULL * 1 - a > b or b is NULL * * NOTES * MT-NOTE: sge_strnullcmp() is MT safe ******************************************************************************/ int sge_strnullcmp(const char *a, const char *b) { if (!a && b) { return -1; } if (a && !b) { return 1; } if (!a && !b) { return 0; } return strcmp(a, b); } /****** uti/string/sge_patternnullcmp() **************************************** * NAME * sge_patternnullcmp() -- like fnmatch * * SYNOPSIS * int sge_patternnullcmp(const char *str, const char *pattern) * * FUNCTION * Like fnmatch() apart from the handling of NULL strings. * These are treated as being less than any not-NULL strings. * Important for sorting lists where NULL strings can occur. * * INPUTS * const char *str - string * const char *pattern - pattern to match * * RESULT * int - result * 0 - strings are the same or both NULL * -1 - a < b or a is NULL * 1 - a > b or b is NULL * * NOTES * MT-NOTE: fnmatch uses static variables, not MT safe *******************************************************************************/ int sge_patternnullcmp(const char *str, const char *pattern) { if (!str && pattern) { return -1; } if (str && !pattern) { return 1; } if (!str && !pattern) { return 0; } return fnmatch(pattern, str, 0); } /****** uti/string/sge_strnullcasecmp() *************************************** * NAME * sge_strnullcasecmp() -- Like strcasecmp() but honours NULL ptrs. * * SYNOPSIS * int sge_strnullcasecmp(const char *a, const char *b) * * FUNCTION * Like strcasecmp() apart from the handling of NULL strings. * These are treated as being less than any not-NULL strings. * Important for sorting lists where NULL strings can occur. * * INPUTS * const char *a - 1st string * const char *b - 2nd string * * RESULT * int - result * 0 - strings are the same minus case or both NULL * -1 - a < b or a is NULL * 1 - a > b or b is NULL * * NOTES * MT-NOTE: sge_strnullcasecmp() is MT safe ******************************************************************************/ int sge_strnullcasecmp(const char *a, const char *b) { if (!a && b) return -1; if (a && !b) return 1; if (!a && !b) return 0; return SGE_STRCASECMP(a, b); } /****** uti/string/sge_is_pattern() ******************************************* * NAME * sge_is_pattern() -- Test if string contains wildcard pattern * * SYNOPSIS * int sge_is_pattern(const char *s) * * FUNCTION * Check whether string 's' contains a wildcard pattern. * * INPUTS * const char *s - string * * RESULT * int - result * 0 - no wildcard pattern * 1 - it is a wildcard pattern * * NOTES * MT-NOTE: sge_is_pattern() is MT safe ******************************************************************************/ bool sge_is_pattern(const char *s) { char c; while ((c = *s++)) { switch (c) { case '*': case '?': case '[': case ']': return true; } } return false; } /****** uti/string/sge_is_expression() ******************************************* * NAME * sge_is_expression() -- Test if string contains expressions & wildcard pattern * * SYNOPSIS * int sge_is_expression(const char *s) * * FUNCTION * Check whether string 's' contains a expressions & a wildcard pattern. * * INPUTS * const char *s - string * * RESULT * int - result * 0 - no wildcard pattern * 1 - it is a wildcard pattern * * NOTES * MT-NOTE: sge_is_expression() is MT safe ******************************************************************************/ bool sge_is_expression(const char *s) { char c; if (s != NULL) { while (*s != '\0') { c = *s; switch (c) { case '*': case '?': case '[': case ']': case '&': case '|': case '!': case '(': case ')': return true; } s++; } } return false; } /****** uti/string/sge_strisint() ********************************************* * NAME * sge_strisint() -- Is string a integer value in characters? * * SYNOPSIS * int sge_strisint(const char *str) * * FUNCTION * May we convert 'str' to int? * * INPUTS * const char *str - string * * RESULT * int - result * 0 - It is no integer * 1 - It is a integer * * NOTES * MT-NOTE: sge_strisint() is MT safe * ******************************************************************************/ int sge_strisint(const char *str) { const char *cp = str; while (*cp) { if (!isdigit((int) *cp++)) { return 0; } } return 1; } /****** uti/string/sge_strtoupper() ******************************************* * NAME * sge_strtoupper() -- Convert the first n to upper case * * SYNOPSIS * void sge_strtoupper(char *buffer, int max_len) * * FUNCTION * Convert the first 'max_len' characters to upper case. * * INPUTS * char *buffer - string * int max_len - number of chars * * NOTES * MT-NOTE: sge_strtoupper() is MT safe ******************************************************************************/ void sge_strtoupper(char *buffer, int max_len) { DENTER(BASIS_LAYER, "sge_strtoupper"); if (buffer != NULL) { int i; int length = MIN(strlen(buffer), max_len); for (i = 0; i < length; i++) { buffer[i] = toupper(buffer[i]); } } DRETURN_VOID; } /****** uti/hostname/sge_strtolower() ******************************************** * NAME * sge_strtolower() -- convert all upper character in the string to lower case * * SYNOPSIS * int sge_strtolower(char *buffer) * * FUNCTION * sge_strtolower() for hostnames. Honours some configuration values: * * INPUTS * char *buffer - string to be lowered * * RESULT * no result, this function modify the argument string * * SEE ALSO * uti/string/sge_strtoupper() * * NOTES: * MT-NOTE: sge_strtolower() is MT safe ******************************************************************************/ void sge_strtolower(char *buffer, int max_len) { DENTER(BASIS_LAYER, "sge_strtolower"); if (buffer != NULL) { int i; for(i=0;buffer[i]!='\0' && i= cpp1) free(*cpp3); free(cpp1); return NULL; } /* copy string */ memcpy(*cpp3, *cpp2, len); cpp3++; cpp2++; } *cpp3 = NULL; return cpp1; } /****** uti/string/sge_strafree() ********************************************* * NAME * sge_strafree() -- Free list of character pointers * * SYNOPSIS * void sge_strafree(char **cpp) * * FUNCTION * Free list of character pointers * * INPUTS * char ***cpp - Pointer to array of string pointers * * NOTES * MT-NOTE: sge_strafree() is MT safe ******************************************************************************/ void sge_strafree(char ***cpp) { if (cpp != NULL && *cpp != NULL) { char **cpp1 = *cpp; while (*cpp1 != NULL) { FREE(*cpp1); cpp1++; } FREE(*cpp); } } /****** uti/string/sge_stramemncpy() ****************************************** * NAME * sge_stramemncpy() -- Find string in string array * * SYNOPSIS * char** sge_stramemncpy(const char *cp, char **cpp, int n) * * FUNCTION * Compare string with string field and return the pointer to * the matched character pointer. Compare exactly n chars * case insensitive. * * INPUTS * const char *cp - string to be found * char **cpp - pointer to array of strings * int n - number of chars * * NOTES: * MT-NOTE: sge_stramemncpy() is MT safe * * RESULT * char** - NULL or pointer a string * * NOTES * MT-NOTE: sge_stramemncpy() is MT safe ******************************************************************************/ char **sge_stramemncpy(const char *cp, char **cpp, int n) { while (*cpp) { if (!memcmp(*cpp, cp, n)) { return cpp; } cpp++; } return NULL; } /****** uti/string/sge_stracasecmp() ****************************************** * NAME * sge_stracasecmp() -- Find string in string array * * SYNOPSIS * char** sge_stracasecmp(const char *cp, char **cpp) * * FUNCTION * Compare string with string field and return the pointer to * the matched character pointer. Compare case sensitive. * * INPUTS * const char *cp - string * char **cpp - pointer to array of strings * * RESULT * char** - NULL or pointer a string * * NOTES * MT-NOTE: sge_stracasecmp() is MT safe ******************************************************************************/ char **sge_stracasecmp(const char *cp, char **cpp) { while (*cpp) { if (!strcasecmp(*cpp, cp)) return cpp; cpp++; } return NULL; } void stra_printf(char *stra[]) { int i = 0; while (stra[i] != NULL) { fprintf(stdout, "%s\n", stra[i]); i++; } } /****** uti/string/stra_from_str() ******************************************** * NAME * str_from_str() -- Extract valid qstat options/paramers from qstat profile. * * SYNOPSIS * char **str_from_str(const char *source_str, const char *delim); * * FUNCTION * Parse string 'source_str' based on delimeter(s) 'delim' and store * resulting tokens in string array 'ret'. Supports comment lines. * * INPUTS * const char *source_str - File content of qstat profile as plain string. * const char *delim - Sequence of characters used to identify tokens * and parameters. * * RESULT * char** - String array containing tokens found based on 'delim'. * * NOTES * It is the caller's responsibilty to free dynamic memory allocated in this * routine. * MT-NOTE: stra_from_str() is MT safe. * *************************************************************************************/ char ** stra_from_str(const char *source_str, const char *delim) { char **ret = NULL; if (source_str != NULL && delim != NULL) { struct saved_vars_s *context1; struct saved_vars_s *context2; const char *token_1 = NULL; const char *token_2 = NULL; int number_of_tokens = 0; int index = 0; /* * Support of comment lines and multiple options per line * in qstat profiles requires two level parsing. First * level works on a per line basis (delimiter `\n') and * sorts out lines starting with comment sign '#'. * * The result of this process is passed to second * level parsing which scans for options and parameters * per line. Delimiters are ' ', '\n' and '\t'. * * We basically need to do this twice: first to determine * the number of valid tokens and then to populate the * string array. * */ /* * Count tokens. */ context1 = NULL; token_1 = sge_strtok_r(source_str, "\n", &context1); while (token_1 != NULL) { if (token_1[0] != '#') { context2 = NULL; token_2 = sge_strtok_r(token_1, " \t", &context2); while (token_2 != NULL) { token_2 = sge_strtok_r(NULL, " \t", &context2); number_of_tokens++; } sge_free_saved_vars(context2); } token_1 = sge_strtok_r(NULL, "\n", &context1); } sge_free_saved_vars(context1); /* * Note that we need to proceed from here even if we got * no valid options/parameters. This is because caller * expects a zero entry string array with stopper as minimum. */ /* malloc array memory */ ret = (char **) malloc(sizeof(char*) * (number_of_tokens + 1)); if (ret != NULL) { /* * Allocate and populate string array. */ index = 0; context1 = NULL; token_1 = sge_strtok_r(source_str, "\n", &context1); while (token_1 != NULL) { if (token_1[0] != '#') { context2 = NULL; token_2 = sge_strtok_r(token_1, " \t", &context2); while (token_2 != NULL) { ret[index] = strdup(token_2); token_2 = sge_strtok_r(NULL, " \t", &context2); index++; } sge_free_saved_vars(context2); } token_1 = sge_strtok_r(NULL, "\n", &context1); } sge_free_saved_vars(context1); ret[index] = NULL; /* Stopper */ } } return ret; } /****** uti/string/sge_compress_slashes() ************************************* * NAME * sge_compress_slashes() -- compresses sequences of slashes * * SYNOPSIS * void sge_compress_slashes(char *str) * * FUNCTION * Compresses sequences of slashes in str to one slash * * INPUTS * char *str - string (e.g. path) * * NOTES * MT-NOTE: sge_compress_slashes() is MT safe *******************************************************************************/ void sge_compress_slashes(char *str) { char *p; int compressed = 0; DENTER(BASIS_LAYER, "sge_compress_slashes"); for (p = str; *p; p++) { while (*p == '/' && *(p+1) == '/') { compressed = 1; *p = '\0'; p++; } if (compressed) { strcat(str, p); compressed = 0; } } DRETURN_VOID; } /****** uti/string/sge_strip_quotes() ***************************************** * NAME * sge_strip_quotes() -- Strip quotes from string * * SYNOPSIS * void sge_strip_quotes(char **pstr) * * FUNCTION * Strip quotes from "pstr". * * INPUTS * char **pstr - string to be modified * * NOTES * MT-NOTE: sge_strip_quotes() is MT safe ******************************************************************************/ void sge_strip_quotes(char **pstr) { char *cp = NULL; char *cp2 = NULL; DENTER(TOP_LAYER, "sge_strip_quotes"); if (!pstr) { DRETURN_VOID; } for (; *pstr; pstr++) { for (cp2 = cp = *pstr; *cp; cp++) { if ((*cp != '"') && (*cp != '\'')) { *cp2++ = *cp; } } *cp2 = '\0'; } DRETURN_VOID; } /****** uti/string/sge_strlen() *********************************************** * NAME * sge_strlen() -- replacement for strlen() * * SYNOPSIS * int sge_strlen(const char *str) * * FUNCTION * replacement for strlen * * INPUTS * const char *str - NULL or pointer to string * * RESULT * int - length of string or 0 if NULL pointer * * NOTES * MT-NOTE: sge_strlen() is MT safe *******************************************************************************/ int sge_strlen(const char *str) { int ret = 0; if (str != NULL) { ret = strlen(str); } return ret; } /* ** problem: modifies input string, ** this is the most frequently used mode ** but allocating extra memory (as it was in ** sge_string2list) should also be possible ** problem: default delimiters should be possible ** note: there is a similar cull function lString2List */ /* ** NAME ** string_list ** PARAMETER ** str - string to be parsed ** delis - string containing delimiters ** pstr - NULL or string array to return ** RETURN ** NULL - error ** char ** - pointer to an array of strings containing ** the string list ** EXTERNAL ** ** DESCRIPTION ** ** NOTES ** MT-NOTE: string_list() is MT safe ** */ char **string_list(char *str, char *delis, char **pstr) { unsigned int i = 0, j = 0; bool is_space = false; int found_first_quote = 0; char **head = NULL; bool done; DENTER(BASIS_LAYER, "string_list"); if (str == NULL) { DRETURN(NULL); } /* skip heading delimiters */ while (str[0] != '\0' && strchr(delis, str[0]) != NULL) { str++; } /* at str end: str either was an empty string or only contained delimiters */ if (str[0] == '\0') { DRETURN(NULL); } /* * not more items than length of string is possible */ if (pstr == NULL) { head = malloc((sizeof(void *)) * (strlen(str) + 1)); if (head == NULL) { DRETURN(NULL); } } else { head = pstr; } done = false; while (!done) { while ((str[i] != '\0') && (strchr(delis, str[i]) != NULL)) { i++; } if (str[i] == '\0') { done = true; break; } head[j] = &str[i]; j++; /* ** parse one string */ is_space = false; while ((str[i] != '\0') && !is_space) { if ((found_first_quote == 0) && (str[i] == '"')) { found_first_quote = 2; } else if ((found_first_quote == 0) && (str[i] == '\'')) { found_first_quote = 1; } i++; /* If we're inside quotes, we don't count spaces. */ if (found_first_quote == 0) { is_space = (bool)(strchr(delis, str[i]) != NULL); } if (((found_first_quote == 2) && (str[i] == '"')) || ((found_first_quote == 1) && (str[i] == '\''))) { found_first_quote = 0; } } if (str[i] == '\0') { done = true; break; } str[i] = '\0'; i++; } head[j] = NULL; DRETURN(head); } /****** uti/string/sge_strerror() ********************************************** * NAME * sge_strerror() -- replacement for strerror * * SYNOPSIS * const char* * sge_strerror(int errnum) * * FUNCTION * Returns a string describing an error condition set by system * calls (errno). * * Wrapper arround strerror. Access to strerrror is serialized by the * use of a mutex variable to make strerror thread safe. * * INPUTS * int errnum - the errno to explain * dstring *buffer - buffer into which the error message is written * * RESULT * const char* - pointer to a string explaining errnum * * NOTES * MT-NOTE: sge_strerror() is MT safe *******************************************************************************/ const char * sge_strerror(int errnum, dstring *buffer) { static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; const char *ret; pthread_mutex_lock(&mtx); ret = strerror(errnum); ret = sge_dstring_copy_string(buffer, ret); pthread_mutex_unlock(&mtx); return ret; } /****** uti/string/sge_str_is_number() ***************************************** * NAME * sge_str_is_number() -- represents the given string a number * * SYNOPSIS * bool sge_str_is_number(const char *string) * * FUNCTION * This function returns true if the given string represents a number. * * INPUTS * const char *string - string * * RESULT * bool - result * true - string represents a number * false - string is not a number * * NOTES * MT-NOTE: sge_str_is_number() is MT safe *******************************************************************************/ bool sge_str_is_number(const char *string) { char *end = NULL; strtod(string, &end); return (*end == '\0') ? true : false; } /****** uti/string/sge_replace_substring() ***************************************** * NAME * sge_replace_substring - replace sub strings in a string * * SYNOPSIS * const char *sge_replace_substring(const char *input, char *old, char *new) * * FUNCTION * Replaces all occurences of old with new. * If old is part of the given string input, a new string is returned * where the replacement is done. * * INPUTS * const char *input - the input string * const char *old - the string to replace * const char *new - the replacement string * * RESULT * NULL, if the input string didn't contain the pattern, * else a newly allocated string containing the input string with replacements. * * NOTES * MT-NOTE: sge_str_is_number() is MT safe * It is the responsibility of the caller to free the returned string! * *******************************************************************************/ const char *sge_replace_substring(const char *input, const char *old, const char *new) { int to_replace = 0; int change, new_len; char *new_string = NULL; char *return_string = NULL; char *source = NULL; char *source_string = NULL; char *tail = NULL; char *current_tail = NULL; /* * Basic sanity checks first. */ if (input == NULL || old == NULL || new == NULL) { return NULL; } /* * Determine number for of substrings to replace. We are * careful NOT to overrun source string. */ source = source_string = (char *)input; tail = source_string + strlen(source_string) - 1; while (source <= tail) { current_tail = source + strlen(old) - 1; if (current_tail > tail) { break; } if (memcmp(old, source, strlen(old)) == 0) { to_replace++; } source++; } if (to_replace == 0) { return NULL; } /* * Calculate size of new string based on number of substrings to replace. */ change = to_replace * (strlen(new) - strlen(old)); new_len = strlen(source_string) + change + 1; /* * Allocate new string and re-shuffle original string. */ return_string = new_string = malloc(new_len); if (new_string == NULL) { return NULL; } memset(new_string, 0x0, new_len); source = source_string; while (source <= tail) { current_tail = source + strlen(old) - 1; if (current_tail <= tail && memcmp(old, source, strlen(old)) == 0) { memcpy(new_string, new, strlen(new)); new_string += strlen(new); source += strlen(old); } else { *new_string = *source; source++; new_string++; } } return return_string; }