| /* $Id$ */ |
| /*****************************************************************************\ |
| * parse_spec.c - configuration file parser |
| ***************************************************************************** |
| * Copyright (C) 2002 The Regents of the University of California. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Morris Jette <jette1@llnl.gov> |
| * UCRL-CODE-226842. |
| * |
| * This file is part of SLURM, a resource management program. |
| * For details, see <http://www.llnl.gov/linux/slurm/>. |
| * |
| * SLURM is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with SLURM; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #if HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <errno.h> |
| |
| #include "src/common/log.h" |
| #include "src/common/parse_spec.h" |
| #include "src/common/xmalloc.h" |
| #include "src/common/xstring.h" |
| |
| |
| #define BUFFER_SIZE 1024 |
| #define SEPCHARS " \n\t" |
| |
| static int _load_long (long *destination, char *keyword, char *in_line) ; |
| static int _load_integer (int *destination, char *keyword, char *in_line) ; |
| static int _load_float (float *destination, char *keyword, char *in_line) ; |
| static char *_strcasestr(char *haystack, char *needle); |
| |
| /* |
| * slurm_parser - parse the supplied specification into keyword/value pairs |
| * only the keywords supplied will be searched for. The supplied |
| * specification is altered, overwriting the keyword and value pairs |
| * with spaces. |
| * spec - pointer to the string of specifications, sets of three values |
| * (as many sets as required): keyword, type, value |
| * IN keyword - string with the keyword to search for including equal sign |
| * (e.g. "name=") |
| * IN type - char with value 'd'==int, 'f'==float, 's'==string, 'l'==long |
| * IN/OUT value - pointer to storage location for value (char **) for type 's' |
| * RET 0 if no error, otherwise errno code |
| * NOTE: terminate with a keyword value of "END" |
| * NOTE: values of type (char *) are xfreed if non-NULL. caller must xfree any |
| * returned value |
| */ |
| int |
| slurm_parser (char *spec, ...) |
| { |
| va_list ap; |
| char *keyword, **str_ptr; |
| int error_code, *int_ptr, type; |
| long *long_ptr; |
| float *float_ptr; |
| |
| error_code = 0; |
| va_start(ap, spec); |
| while (error_code == 0) { |
| keyword = va_arg(ap, char *); |
| if (strcmp (keyword, "END") == 0) |
| break; |
| type = va_arg(ap, int); |
| switch (type) { |
| case 'd': |
| int_ptr = va_arg(ap, int *); |
| error_code = _load_integer(int_ptr, keyword, spec); |
| break; |
| case 'f': |
| float_ptr = va_arg(ap, float *); |
| error_code = _load_float(float_ptr, keyword, spec); |
| break; |
| case 'l': |
| long_ptr = va_arg(ap, long *); |
| error_code = _load_long(long_ptr, keyword, spec); |
| break; |
| case 's': |
| str_ptr = va_arg(ap, char **); |
| error_code = load_string (str_ptr, keyword, spec); |
| break; |
| default: |
| fatal ("parse_spec: invalid type %c", type); |
| } |
| } |
| va_end(ap); |
| return error_code; |
| } |
| |
| |
| /* |
| * _load_float - parse a string for a keyword, value pair, and load the float |
| * value |
| * IN keyword - string to search for |
| * IN/OUT in_line - string to search for keyword, the keyword and value |
| * (if present) are overwritten by spaces |
| * OUT destination - set to value, no change if value not found |
| * RET 0 if no error, otherwise an error code |
| * NOTE: in_line is overwritten, do not use a constant |
| */ |
| static int |
| _load_float (float *destination, char *keyword, char *in_line) |
| { |
| char scratch[BUFFER_SIZE]; /* scratch area for parsing the input line */ |
| char *str_ptr1, *str_ptr2, *str_ptr3; |
| int i, str_len1, str_len2; |
| |
| str_ptr1 = (char *) _strcasestr (in_line, keyword); |
| if (str_ptr1 != NULL) { |
| str_len1 = strlen (keyword); |
| strcpy (scratch, str_ptr1 + str_len1); |
| if ((scratch[0] < '0') && (scratch[0] > '9')) { |
| error ("_load_float: bad value for keyword %s", |
| keyword); |
| return EINVAL; |
| } |
| str_ptr2 = (char *) strtok_r (scratch, SEPCHARS, &str_ptr3); |
| str_len2 = strlen (str_ptr2); |
| *destination = (float) strtod (scratch, (char **) NULL); |
| for (i = 0; i < (str_len1 + str_len2); i++) { |
| str_ptr1[i] = ' '; |
| } |
| } |
| return 0; |
| } |
| |
| |
| /* |
| * _load_integer - parse a string for a keyword, value pair, and load the |
| * integer value |
| * OUT destination - location into which result is stored |
| * set to 1 if keyword found without value, |
| * set to -1 if keyword followed by "unlimited" |
| * IN keyword - string to search for |
| * IN/OUT in_line - string to search for keyword, the keyword and value |
| * (if present) are overwritten by spaces |
| * RET 0 if no error, otherwise an error code |
| */ |
| static int |
| _load_integer (int *destination, char *keyword, char *in_line) |
| { |
| char scratch[BUFFER_SIZE]; /* scratch area for parsing the input line */ |
| char *str_ptr1, *str_ptr2, *str_ptr3; |
| int i, str_len1, str_len2; |
| |
| str_ptr1 = (char *) _strcasestr (in_line, keyword); |
| if (str_ptr1 != NULL) { |
| str_len1 = strlen (keyword); |
| strcpy (scratch, str_ptr1 + str_len1); |
| if ((scratch[0] == '\0') || |
| (isspace ((int) scratch[0]))) { |
| /* keyword with no value set */ |
| *destination = 1; |
| str_len2 = 0; |
| } |
| else { |
| str_ptr2 = (char *) strtok_r (scratch, SEPCHARS, |
| &str_ptr3); |
| str_len2 = strlen (str_ptr2); |
| if (strcasecmp (str_ptr2, "UNLIMITED") == 0) |
| *destination = -1; |
| else if ((str_ptr2[0] >= '0') && |
| (str_ptr2[0] <= '9')) { |
| *destination = (int) strtol (scratch, |
| (char **) NULL, |
| 10); |
| } |
| else { |
| error ("_load_integer: bad value for keyword %s", |
| keyword); |
| return EINVAL; |
| } |
| } |
| |
| for (i = 0; i < (str_len1 + str_len2); i++) { |
| str_ptr1[i] = ' '; |
| } |
| } |
| return 0; |
| } |
| |
| |
| /* |
| * _load_long - parse a string for a keyword, value pair, and load the |
| * long value |
| * IN/OUT destination - location into which result is stored, set to value, |
| * no change if value not found, |
| * set to 1 if keyword found without value, |
| * set to -1 if keyword followed by "unlimited" |
| * IN keyword - string to search for |
| * IN/OUR in_line - string to search for keyword, the keyword and value |
| * (if present) are overwritten by spaces |
| * RET 0 if no error, otherwise an error code |
| * NOTE: in_line is overwritten, do not use a constant |
| */ |
| static int |
| _load_long (long *destination, char *keyword, char *in_line) |
| { |
| char scratch[BUFFER_SIZE]; /* scratch area for parsing the input line */ |
| char *str_ptr1, *str_ptr2, *str_ptr3; |
| int i, str_len1, str_len2; |
| |
| str_ptr1 = (char *) _strcasestr (in_line, keyword); |
| if (str_ptr1 != NULL) { |
| str_len1 = strlen (keyword); |
| strcpy (scratch, str_ptr1 + str_len1); |
| if ((scratch[0] == '\0') || |
| (isspace ((int) scratch[0]))) { |
| /* keyword with no value set */ |
| *destination = 1; |
| str_len2 = 0; |
| } |
| else { |
| str_ptr2 = (char *) strtok_r (scratch, SEPCHARS, |
| &str_ptr3); |
| str_len2 = strlen (str_ptr2); |
| if (strcasecmp (str_ptr2, "UNLIMITED") == 0) |
| *destination = -1L; |
| else if ((str_ptr2[0] == '-') || |
| ((str_ptr2[0] >= '0') && |
| (str_ptr2[0] <= '9'))) { |
| *destination = strtol (scratch, |
| (char **) NULL, 10); |
| } |
| else { |
| error ("_load_long: bad value for keyword %s", |
| keyword); |
| return EINVAL; |
| } |
| } |
| |
| for (i = 0; i < (str_len1 + str_len2); i++) { |
| str_ptr1[i] = ' '; |
| } |
| } |
| return 0; |
| } |
| |
| |
| /* |
| * load_string - parse a string for a keyword, value pair, and load the |
| * char value |
| * IN/OUT destination - location into which result is stored, set to value, |
| * no change if value not found, if destination had previous value, |
| * that memory location is automatically freed |
| * IN keyword - string to search for |
| * IN/OUT in_line - string to search for keyword, the keyword and value |
| * (if present) are overwritten by spaces |
| * RET 0 if no error, otherwise an error code |
| * NOTE: destination must be free when no longer required |
| * NOTE: if destination is non-NULL at function call time, it will be freed |
| * NOTE: in_line is overwritten, do not use a constant |
| */ |
| int |
| load_string (char **destination, char *keyword, char *in_line) |
| { |
| char scratch[BUFFER_SIZE];/* scratch area for parsing the input line */ |
| char *str_ptr1, *str_ptr2, *str_ptr3; |
| int i, str_len1, str_len2; |
| |
| str_ptr1 = (char *) _strcasestr (in_line, keyword); |
| if (str_ptr1 != NULL) { |
| int quoted = 0; |
| str_len1 = strlen (keyword); |
| if (str_ptr1[str_len1] == '"') |
| quoted = 1; |
| strcpy (scratch, str_ptr1 + str_len1 + quoted); |
| if (quoted) |
| str_ptr2 = strtok_r (scratch, "\042\n", &str_ptr3); |
| else |
| str_ptr2 = strtok_r (scratch, SEPCHARS, &str_ptr3); |
| if ((str_ptr2 == NULL) || |
| ((str_len2 = strlen (str_ptr2))== 0)){ |
| info ("load_string : keyword %s lacks value", |
| keyword); |
| return EINVAL; |
| } |
| xfree (destination[0]); |
| destination[0] = xstrdup(str_ptr2); |
| for (i = 0; i < (str_len1 + str_len2 + quoted); i++) |
| str_ptr1[i] = ' '; |
| if (quoted && (str_ptr1[i] == '"')) |
| str_ptr1[i] = ' '; |
| } |
| return 0; |
| } |
| |
| /* case insensitve version of strstr() */ |
| static char * |
| _strcasestr(char *haystack, char *needle) |
| { |
| int hay_inx, hay_size = strlen(haystack); |
| int need_inx, need_size = strlen(needle); |
| char *hay_ptr = haystack; |
| |
| for (hay_inx=0; hay_inx<hay_size; hay_inx++) { |
| for (need_inx=0; need_inx<need_size; need_inx++) { |
| if (tolower((int) hay_ptr[need_inx]) != |
| tolower((int) needle [need_inx])) |
| break; /* mis-match */ |
| } |
| |
| if (need_inx == need_size) /* it matched */ |
| return hay_ptr; |
| else /* keep looking */ |
| hay_ptr++; |
| } |
| |
| return NULL; /* no match anywhere in string */ |
| } |