/* * scamper_options.c: code to handle parsing of options * * $Id: scamper_options.c,v 1.2 2006/12/04 08:21:39 mjl Exp $ * * Matthew Luckie * * Copyright (C) 2006 The University of Waikato * * This program 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, version 2. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #if defined(__APPLE__) #include #endif #include "scamper_options.h" #include "utils.h" /* * opt_add * * routine to place the logic for putting together a list holding parsed * options. */ static int opt_add(scamper_option_out_t **head, scamper_option_out_t **tail, int id, char *str) { assert(head != NULL); assert(tail != NULL); if(*tail == NULL) { assert(*head == NULL); if((*head = malloc(sizeof(scamper_option_out_t))) == NULL) { return -1; } *tail = *head; } else { if(((*tail)->next = malloc(sizeof(scamper_option_out_t))) == NULL) { return -1; } *tail = (*tail)->next; } (*tail)->next = NULL; (*tail)->id = id; (*tail)->str = str; return 0; } /* * opt_parse_param * * this code is used to parse out the parameter pointed to by str based on * the supplied parameter type. the next word in the string is returned * in 'next' */ static int opt_parse_param(int type, char **str, char **next) { char *tmp = *str; char delim; if(type == SCAMPER_OPTION_TYPE_NUM) { while(isdigit((int)*tmp) != 0) { tmp++; } /* if there are no digits in this parameter, then we have a problem */ if(tmp == *str) { goto err; } /* if the digit we stopped on is not whitespace, we have a problem */ if(*tmp != '\0') { if(isspace((int)*tmp) == 0) { goto err; } } } else if(type == SCAMPER_OPTION_TYPE_STR) { /* * if the first character is a quoting character, then the string is * terminated by the same quoting character */ if(tmp[0] == '"' || tmp[0] == '\'') { /* record the type of quoting character, and then advance past it */ delim = tmp[0]; tmp++; *str = tmp; /* * read the string until we either get the other quoting character, * or the end of the string. if we don't get the other quoting * character then we have a problem * * XXX: when we fall out of the top-level if statement, the character * pointed to by tmp will be set to null; this corresponds to the * character used for quoting. */ while(tmp[0] != delim && tmp[0] != '\0') tmp++; if(tmp[0] == '\0') goto err; } else { *next = string_nextword(*str); return 0; } } /* if we got to the end of the argument list, then nothing else comes next */ if(tmp[0] == '\0') { *next = NULL; return 0; } /* null terminate the option parameter string */ tmp[0] = '\0'; tmp++; /* * skip past whitespace and advance to the next string in the option. * if there is nothing else, then *next is set to NULL. */ while(isspace((int)*tmp) != 0) tmp++; if(tmp[0] != '\0') *next = tmp; else *next = NULL; return 0; err: *next = NULL; return -1; } /* * scamper_options_parse * * given the options string, and a definition of what option strings are valid, * parse the options out and return a linked list of the options in opts_out. * * this code is a horrible mess of goto statements. */ int scamper_options_parse(char *str, const scamper_option_in_t *opts, const int cnt, scamper_option_out_t **opts_out, char **stop) { scamper_option_out_t *head = NULL; scamper_option_out_t *tail = NULL; char *next; int i; /* to begin with, get to the first non-whitespace character */ while(*str != '\0' && isspace((int)*str) != 0) { str++; } /* if it turns out there are no options, then return now */ if(*str == '\0') { goto done; } /* begin parsing the options */ do { /* * first, ensure the string begins with a hyphen to denote an option. * this is done before calling string_nextword since the non-options * part of the string needs to be passed back unmodified (which this * will be if the first character is not a hyphen) */ if(str[0] != '-') { break; } /* * null terminate the current word, and figure out where the next * word begins */ next = string_nextword(str); /* * the code supports both long and short options, so descriminate * appropriately. */ if(str[1] == '-') { /* look for an option that matches the string */ for(i=0; inext; } return i; } /* * scamper_options_free * * simple function to free up the option_out linked list passed in, which * was allocated by scamper_options_parse. */ void scamper_options_free(scamper_option_out_t *opts) { scamper_option_out_t *tmp; while(opts != NULL) { tmp = opts->next; free(opts); opts = tmp; } return; }