/* * Copyright (C) 2001 - 2007 Tomasz Kojm * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #if HAVE_CONFIG_H #include "clamav-config.h" #endif #include #include #include #define _GNU_SOURCE #include "getopt.h" #include "options.h" #include "output.h" static int register_option(struct optstruct *opt, const char *optlong, char optshort, const struct option *options_long, const char * const *accepted_long, const char * const *deprecated_long) { struct optnode *newnode; int i, found; const char *longname = NULL; if(optshort) { for(i = 0; options_long[i].name; i++) { if(options_long[i].val == optshort) { longname = options_long[i].name; break; } } } else longname = optlong; if(!longname) { mprintf("!register_option: No long option for -%c\n", optshort); return -1; } if(accepted_long) { found = 0; for(i = 0; accepted_long[i]; i++) if(!strcmp(accepted_long[i], longname)) { found = 1; break; } if(!found) { if(optshort) mprintf("WARNING: Ignoring option --%s (-%c)\n", longname, optshort); else mprintf("WARNING: Ignoring option --%s\n", longname); return 0; } } if(deprecated_long) { found = 0; for(i = 0; deprecated_long[i]; i++) { if(!strcmp(deprecated_long[i], longname)) { found = 1; break; } } if(found) { if(optshort) mprintf("WARNING: Ignoring deprecated option --%s (-%c)\n", longname, optshort); else mprintf("WARNING: Ignoring deprecated option --%s\n", longname); return 0; } } newnode = (struct optnode *) malloc(sizeof(struct optnode)); if(!newnode) { mprintf("!register_long_option: malloc failed\n"); return -1; } newnode->optshort = optshort; if(optarg) { newnode->optarg = (char *) malloc(strlen(optarg) + 1); if(!newnode->optarg) { mprintf("!register_long_option: malloc failed\n"); free(newnode); return -1; } strcpy(newnode->optarg, optarg); } else newnode->optarg = NULL; newnode->optlong = (char *) malloc(strlen(longname) + 1); if(!newnode->optlong) { mprintf("ERROR: register_long_option: malloc failed\n"); free(newnode->optarg); free(newnode); return -1; } strcpy(newnode->optlong, longname); newnode->next = opt->optlist; opt->optlist = newnode; return 0; } void opt_free(struct optstruct *opt) { struct optnode *handler, *prev; if(!opt) return; handler = opt->optlist; while(handler) { if(handler->optarg) free(handler->optarg); if(handler->optlong) free(handler->optlong); prev = handler; handler = handler->next; free(prev); } if(opt->filename) free(opt->filename); free(opt); } struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long, const char * const *deprecated_long) { int ret, opt_index, i, len; struct optstruct *opt; const char *longname; opt = (struct optstruct *) calloc(1, sizeof(struct optstruct)); if(!opt) { mprintf("!opt_parse: calloc failed\n"); return NULL; } while(1) { opt_index = 0; ret = getopt_long(argc, argv, getopt_short, options_long, &opt_index); if(ret == -1) break; switch(ret) { case 0: if(register_option(opt, options_long[opt_index].name, 0, options_long, accepted_long, deprecated_long) == -1) { opt_free(opt); return NULL; } break; default: if(strchr(getopt_short, ret)) { if(opt_index) longname = options_long[opt_index].name; else longname = NULL; if(register_option(opt, longname, ret, options_long, accepted_long, deprecated_long) == -1) { opt_free(opt); return NULL; } } else { mprintf("!Unknown option passed.\n"); opt_free(opt); return NULL; } } } if(optind < argc) { len = 0; /* count length of non-option arguments */ for(i = optind; i < argc; i++) len += strlen(argv[i]); len += argc - optind - 1; opt->filename = (char *) calloc(len + 64, sizeof(char)); if(!opt->filename) { mprintf("!opt_parse: calloc failed\n"); opt_free(opt); return NULL; } for(i = optind; i < argc; i++) { strncat(opt->filename, argv[i], strlen(argv[i])); if(i != argc - 1) strncat(opt->filename, "\t", 1); } } return opt; } int opt_check(const struct optstruct *opt, const char *optlong) { struct optnode *handler; if(!opt) { mprintf("!opt_check: opt == NULL\n"); return 0; } handler = opt->optlist; while(handler) { if(handler->optlong && !strcmp(handler->optlong, optlong)) return 1; handler = handler->next; } return 0; } char *opt_arg(const struct optstruct *opt, const char *optlong) { struct optnode *handler; if(!opt) { mprintf("!opt_arg: opt == NULL\n"); return 0; } handler = opt->optlist; while(handler) { if(handler->optlong && !strcmp(handler->optlong, optlong)) return handler->optarg; handler = handler->next; } return NULL; } char *opt_firstarg(const struct optstruct *opt, const char *optlong, const struct optnode **optnode) { const struct optnode *handler; if(!opt) { mprintf("!opt_firstarg: opt == NULL\n"); return 0; } handler = opt->optlist; while(handler) { if(handler->optlong && !strcmp(handler->optlong, optlong)) { *optnode = handler; return handler->optarg; } handler = handler->next; } *optnode = NULL; return NULL; } char *opt_nextarg(const struct optnode **optnode, const char *optlong) { struct optnode *handler; if(!optnode || !*optnode) { mprintf("!opt_nextarg: *optnode == NULL\n"); return 0; } handler = (*optnode)->next; while(handler) { if(handler->optlong && !strcmp(handler->optlong, optlong)) { *optnode = handler; return handler->optarg; } handler = handler->next; } *optnode = NULL; return NULL; }