Sat, 19 Feb 2000 23:23:29 +0100
trunk: changeset 4
- Added include support in config file parser
- Added scatn()
- Fixed remalloczero()
- Fixed is_end() in numparser2.h -- EOF case was missing
/* * libtu/optparser.c * * Copyright (c) Tuomo Valkonen 1999-2000. * * This file is distributed under the terms of the "Artistic License". * See the included file LICENSE for details. */ #include <string.h> #include <stdlib.h> #include "include/util.h" #include "include/misc.h" #include "include/optparser.h" #include "include/output.h" #define O_CHAINABLE(o) (o->flags&OPT_CHAINABLE) #define O_IMM_ARG(o) (o->flags&OPT__IMM_ARG) #define O_NO_DASH(o) (o->flags&OPT_NO_DASH) #define O_MIDLONG(o) (o->flags&OPT_MIDLONG) #define O_NO_LONG(o) (o->flags&OPT_NO_LONG) #define O_ARGS(o) (o->flags&OPT_OPT_ARG) #define O_ARG(o) (o->flasg&OPT_ARG) #define O_OPT_ARG(o) (O_ARGS(o)==OPT_OPT_ARG) #define O_ID(o) (o->optid) static const OptParserOpt *o_opts=NULL; static char *const *o_current=NULL; static int o_left=0; static const char* o_chain_ptr=NULL; static int o_args_left=0; static const char*o_tmp=NULL; static int o_error=0; /* */ void optparser_init(int argc, char *const argv[], const OptParserOpt *opts) { o_opts=opts; o_current=argv+1; o_left=argc-1; o_chain_ptr=NULL; o_args_left=0; o_tmp=NULL; } /* */ static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o) { for(;O_ID(o);o++){ if(O_CHAINABLE(o) && O_ID(o)==p) return o; } return NULL; } static bool valid_chain(const char *p, const OptParserOpt *o) { while(*p!='\0'){ if(!find_chain_opt(*p, o)) return FALSE; p++; } return TRUE; } static bool is_option(const char *p) { if(p==NULL) return FALSE; if(*p++!='-') return FALSE; if(*p++!='-') return FALSE; if(*p=='\0') return FALSE; return TRUE; } /* */ int optparser_get_opt() { #define RET(X) return o_tmp=p, o_error=X const char *p, *p2=NULL; bool lo=FALSE, dash=TRUE; const OptParserOpt *o; int l; while(o_args_left) optparser_get_arg(); o_tmp=NULL; /* Are we doing a chain (i.e. opt. of style 'tar xzf') ? */ if(o_chain_ptr!=NULL){ p=o_chain_ptr++; if(!*o_chain_ptr) o_chain_ptr=NULL; o=find_chain_opt(*p, o_opts); if(o==NULL) RET(E_OPT_INVALID_CHAIN_OPTION); goto do_arg; } if(o_left<1) return OPT_ID_END; o_left--; p=*o_current++; if(*p!='-'){ /* foo */ dash=FALSE; }else if(*(p+1)=='-'){ /* --foo */ if(*(p+2)=='\0'){ /* -- */ o_args_left=o_left; RET(OPT_ID_ARGUMENT); } lo=TRUE; p2=p+2; }else{ /* -foo */ if(*(p+1)=='\0'){ /* - */ o_args_left=1; RET(OPT_ID_ARGUMENT); } p2=p+1; } o=o_opts; again: for(;O_ID(o);o++){ if(lo){ /* Do long option (--foo=bar) */ if(o->longopt==NULL) continue; l=strlen(o->longopt); if(strncmp(p2, o->longopt, l)!=0) continue; if(O_NO_LONG(o)) RET(E_OPT_INVALID_OPTION); if(p2[l]=='\0'){ if(O_ARGS(o)==OPT_ARG) RET(E_OPT_MISSING_ARGUMENT); return O_ID(o); }else if(p2[l]=='='){ if(!O_ARGS(o)) RET(E_OPT_UNEXPECTED_ARGUMENT); if(p2[l+1]=='\0') RET(E_OPT_MISSING_ARGUMENT); o_tmp=p2+l+1; o_args_left=1; return O_ID(o); } }else{ /* Do midlong option (-foobar) */ if(dash && o->longopt!=NULL && strcmp(p2, o->longopt)==0){ if(!O_MIDLONG(o)) RET(E_OPT_INVALID_OPTION); goto do_arg; } /* Do short option (-f) */ if((!dash && !O_NO_DASH(o)) || *p2!=O_ID(o)) continue; if(*(p2+1)!='\0'){ if(O_CHAINABLE(o) && valid_chain(p2+1, o_opts)){ o_chain_ptr=p2+1; }else if(O_IMM_ARG(o)){ o_tmp=p2+1; o_args_left=1; return O_ID(o); }else{ continue; } } do_arg: if(!O_ARGS(o)) return O_ID(o); if(O_ARGS(o)==OPT_ARG){ if(o_left==0) RET(E_OPT_MISSING_ARGUMENT); }else{ if(!o_left || is_option(*o_current)) return O_ID(o); } o_args_left=1; return O_ID(o); } } if(dash) RET(E_OPT_INVALID_OPTION); RET(OPT_ID_ARGUMENT); #undef RET } /* */ const char* optparser_get_arg() { const char *p; if(o_tmp!=NULL){ /* If o_args_left==0, then were returning an invalid option * otherwise an immediate argument (e.g. -funsigned-char * where '-f' is the option and 'unsigned-char' the argument) */ if(o_args_left>0) o_args_left--; p=o_tmp; o_tmp=NULL; return p; } if(o_args_left<1 || o_left<1) return NULL; o_left--; o_args_left--; return *o_current++; } /* */ static void warn_arg(const char *e) { const char*p=optparser_get_arg(); if(p==NULL) warn("%s (null)", e); else warn("%s \'%s\'", e, p); } static void warn_opt(const char *e) { if(o_chain_ptr!=NULL && o_tmp!=NULL) warn("%s \'-%c\'", e, *o_tmp); else warn_arg(e); } void optparser_print_error() { switch(o_error){ case E_OPT_INVALID_OPTION: warn_opt(TR("Invalid option")); break; case E_OPT_INVALID_CHAIN_OPTION: warn_opt(TR("Invalid option in chain (this cannot happen)")); break; case E_OPT_SYNTAX_ERROR: warn_arg(TR("Syntax error while parsing")); break; case E_OPT_MISSING_ARGUMENT: warn_opt(TR("Missing argument to")); break; case E_OPT_UNEXPECTED_ARGUMENT: warn_opt(TR("No argument expected to")); break; case OPT_ID_ARGUMENT: warn(TR("Unexpected argument")); break; default: warn(TR("(unknown error)")); } o_tmp=NULL; o_error=0; }