shared/options.c
7b8edc5c
 /*
d5a2f640
  *  Copyright (C) 2001 - 2007 Tomasz Kojm <tkojm@clamav.net>
7b8edc5c
  *
  *  This program is free software; you can redistribute it and/or modify
bb34cb31
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
7b8edc5c
  *
  *  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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #define _GNU_SOURCE
 #include "getopt.h"
 
 #include "options.h"
 #include "output.h"
 
 
6f030f8a
 static int register_option(struct optstruct *opt, const char *optlong, char optshort, const struct option *options_long, const char * const *accepted_long)
7b8edc5c
 {
 	struct optnode *newnode;
 	int i, found = 0;
 	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) {
 	for(i = 0; accepted_long[i]; i++)
 	    if(!strcmp(accepted_long[i], longname))
 		found = 1;
 
 	if(!found) {
d5a2f640
 	    if(optshort)
 		mprintf("WARNING: Ignoring option --%s (-%c)\n", longname, optshort);
 	    else
 		mprintf("WARNING: Ignoring option --%s\n", longname);
 
7b8edc5c
 	    return 0;
 	}
     }
 
8ca8a18e
     newnode = (struct optnode *) malloc(sizeof(struct optnode));
7b8edc5c
     if(!newnode) {
8ca8a18e
 	mprintf("!register_long_option: malloc failed\n");
7b8edc5c
 	return -1;
     }
 
     newnode->optshort = optshort;
 
     if(optarg) {
8ca8a18e
 	newnode->optarg = (char *) malloc(strlen(optarg) + 1);
7b8edc5c
 	if(!newnode->optarg) {
8ca8a18e
 	    mprintf("!register_long_option: malloc failed\n");
7b8edc5c
 	    free(newnode);
 	    return -1;
 	}
 	strcpy(newnode->optarg, optarg);
     } else
 	newnode->optarg = NULL;
 
8ca8a18e
     newnode->optlong = (char *) malloc(strlen(longname) + 1);
7b8edc5c
     if(!newnode->optlong) {
8ca8a18e
 	mprintf("ERROR: register_long_option: malloc failed\n");
7b8edc5c
 	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);
 }
 
6f030f8a
 struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long)
7b8edc5c
 {
 	int ret, opt_index, i, len;
 	struct optstruct *opt;
 	const char *longname;
 
 
8ca8a18e
     opt = (struct optstruct *) calloc(1, sizeof(struct optstruct));
7b8edc5c
     if(!opt) {
8ca8a18e
 	mprintf("!opt_parse: calloc failed\n");
7b8edc5c
 	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) == -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;
 
d5a2f640
 		    if(register_option(opt, longname, ret, options_long, accepted_long) == -1) {
7b8edc5c
 			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;
8ca8a18e
 	opt->filename = (char *) calloc(len + 64, sizeof(char));
7b8edc5c
 	if(!opt->filename) {
8ca8a18e
 	    mprintf("!opt_parse: calloc failed\n");
7b8edc5c
 	    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;
 }
 
fc83da82
 int opt_check(const struct optstruct *opt, const char *optlong)
7b8edc5c
 {
 	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;
 }
 
fc83da82
 char *opt_arg(const struct optstruct *opt, const char *optlong)
7b8edc5c
 {
 	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)
 {
6f030f8a
 	const struct optnode *handler;
7b8edc5c
 
     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;
 }