blob: f5836ff0d2dd87f6af16a403301d1dd4393b2ce6 [file] [log] [blame]
/* $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 */
}