⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clif.c

📁 linux下traceroute的实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Copyright (c)  2000, 2003		Dmitry Butskoy					<buc@citadel.stu.neva.ru>    License:  LGPL v2.1 or any later    See COPYING.LIB for the status of this software.*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <stdarg.h>#include "clif.h"#if 1	/*  Bad idea, anyway...  */#define MAX_ARGC_NUMBER	256typedef unsigned char _CLIF_index;#else#define MAX_ARGC_NUMBER	(4096 / 5 + 1)	/*  POSIX ARG_MAX >= 4096 ...  */typedef unsigned short _CLIF_index;#endif/*  This is needed for some print info functions.   This is ugly for thread-safe (is it really actual on program invoking?),   and for several CLIF_parse_cmdline invoking... But foo on this. Yeah...*/static struct {	int argc;	char **argv;	CLIF_option *option_list;	CLIF_argument *argument_list;	unsigned int parse_flags;} curr = { 0, };	static void err_report (const char *format, ...) {	va_list ap;	if (curr.parse_flags & CLIF_SILENT)		return;	va_start (ap, format);	vfprintf (stderr, format, ap);	va_end (ap);	fprintf (stderr, "\n");	return;}/*  info generation stuff...   */#define SHORT_PLUS_MINUS	"+/-"#define LONG_PLUS_MINUS		"++/--"#define EXCL_DLM		" | "static char *show_short (const CLIF_option *optn) {	static char buf[80];	char *p = buf;	unsigned int flags = optn->flags | curr.parse_flags;	if (optn->function_plus) {	    if (!optn->function)  *p++ = '+';	    else {		strcpy (p, SHORT_PLUS_MINUS);		p += sizeof (SHORT_PLUS_MINUS) - 1;	    }	} else	    *p++ = '-';	*p++ = optn->short_opt[0];	if (optn->arg_name) {	    char *endp = buf + sizeof (buf) - sizeof (",...]");	    const char *s;	    if (!(flags & _CLIF_STRICT_JOIN_ARG))  *p++ = ' ';	    if (flags & CLIF_OPTARG)  *p++ = '[';	    s = optn->arg_name;	    while (*s && p < endp)  *p++ = *s++;	    if (flags & CLIF_SEVERAL) {		strcpy (p, ",...");		p += sizeof (",...") - 1;	/*  last '\0' ...  */	    }	    if (flags & CLIF_OPTARG)  *p++ = ']';	}	*p = '\0';	return buf;}	static char *show_long (const CLIF_option *optn) {	static char buf[80];	char *p = buf;	char *endp;	const char *s;	unsigned int flags = optn->flags | curr.parse_flags;	if (!(flags & _CLIF_STRICT_KEYWORD)) {	    if (!(flags & _CLIF_STRICT_ONEDASH)) {		if (optn->function_plus) {		    if (!optn->function)  {  *p++ = '+'; *p++ = '+';  }		    else {			strcpy (p, LONG_PLUS_MINUS);			p += sizeof (LONG_PLUS_MINUS) - 1;		    }		} else {  *p++ = '-'; *p++ = '-';  }	    } else {		if (optn->function_plus) {		    if (!optn->function)  *p++ = '+';		    else {			strcpy (p, SHORT_PLUS_MINUS);			p += sizeof (SHORT_PLUS_MINUS) - 1;		    }		} else  *p++ = '-';	    }	}	s = optn->long_opt;	endp = buf + sizeof (buf) - sizeof (" [");	while (*s && p < endp)  *p++ = *s++;	if (optn->arg_name) {	    if (flags & _CLIF_STRICT_NOEQUAL) {		*p++ = ' ';		if (flags & CLIF_OPTARG)  *p++ = '[';	    } else {		if (flags & CLIF_OPTARG)  *p++ = '[';		*p++ = '=';	    }	    s = optn->arg_name;	    endp = buf + sizeof (buf) - sizeof (",...]");	    while (*s && p < endp)  *p++ = *s++;	    if (flags & CLIF_SEVERAL) {		strcpy (p, ",...");		p += sizeof (",...") - 1;	/*  last '\0' ...  */	    }	    if (flags & CLIF_OPTARG)  *p++ = ']';	}	*p = '\0';	return buf;}static char *show_excl (const CLIF_option *option_list, int *cnt_p) {	static char buf[256];	const CLIF_option *optn;	char *p = buf;	char *endp = buf + sizeof (buf) - sizeof (EXCL_DLM);	int excl_cnt = 0;	*p = '\0';	if (cnt_p)  *cnt_p = 0;	if (!option_list)  return buf;	for (optn = option_list; optn->short_opt || optn->long_opt; optn++) {	    char *s;	    if (!(optn->flags & CLIF_EXCL))  continue;	    if (optn->short_opt)  s = show_short (optn);	    else  s = show_long (optn);	    if (excl_cnt > 0) {	    /*  i.e., second etc...  */		    strcpy (p, EXCL_DLM);		    p += sizeof (EXCL_DLM) - 1;	    }	    while (*s && p < endp)  *p++ = *s++;	    excl_cnt++;	}	*p = '\0';	if (cnt_p)  *cnt_p = excl_cnt;	return buf;}static int is_keyword (const CLIF_option *optn) {	unsigned int flags = optn->flags | curr.parse_flags;	return  (flags & _CLIF_STRICT_KEYWORD) != 0;}static void err_bad_opt (const char *arg, char c, int n) {	char sym = (*arg == '+') ? '+' : '-';	if (c)  err_report ("Bad option `%c%c' (argc %d)", sym, c, n);	else {	    char *p = strchr (arg, '=');	    const char *type = (*arg == sym) ? "option" : "keyword";	    if (p)		err_report ("Bad %s `%s' (with arg `%s') (argc %d)",							type, arg, p + 1, n);	    else		err_report ("Bad %s `%s' (argc %d)", type, arg, n);	}}static void err_bad_arg (const CLIF_option *optn, char c, int n) {	CLIF_option tmp = *optn;	char ss[80];	char *s;	tmp.arg_name = NULL;	if (c) {	    s = show_short (&tmp);	/*  always without arg...  */	    strncpy (ss, s, sizeof (ss));	    s = show_short (optn);	} else {	    s = show_long (&tmp);	/*  always without arg...  */	    strncpy (ss, s, sizeof (ss));	    s = show_long (optn);	}	err_report ("%s `%s' (argc %d) requires an argument: `%s'",		    (c || !is_keyword (optn)) ? "Option" : "Keyword", ss, n, s);}	static void err_bad_res (const CLIF_option *optn, char c,					const char *opt_arg, int n) {	CLIF_option tmp = *optn;	char *ss;	const char *type;	tmp.arg_name = NULL;	if (c) {	    ss = show_short (&tmp);	    type = "option";	} else {	    ss = show_long (&tmp);	    type = is_keyword (optn) ? "keyword" : "option";	}	if (optn->arg_name)	    err_report ("Cannot handle `%s' %s with arg `%s' (argc %d)",							ss, type, opt_arg, n);	else	    err_report ("Cannot handle `%s' %s (argc %d)", ss, type, n);}static void err_bad_excl (const CLIF_option *optn, char c, int n) {	CLIF_option tmp = *optn;	char *ss;	char *excl = show_excl (curr.option_list, 0);				/*  Note: show_(short|long)() nested!!! */	tmp.arg_name = NULL;	if (c)  ss = show_short (&tmp);	else  ss = show_long (&tmp);	err_report ("%s `%s' (argc %d): Only one of:\n    %s\n"		    "may be specified.",		    (c || !is_keyword (optn)) ? "Option" : "Keyword",							    ss, n, excl);}static CLIF_option *find_long (char *arg, char **arg_p,				unsigned int match, unsigned int nomatch) {	CLIF_option *optn;	CLIF_option *abbrev = NULL;	char *abbrev_arg = NULL;	int abbrev_found = 0;	for (optn = curr.option_list;		optn->short_opt || optn->long_opt;		    optn++	) {	    char *a;	    const char *o;	    unsigned int flags;	    if (!optn->long_opt)  continue;	    flags = curr.parse_flags | optn->flags;	    if (flags & nomatch)  continue;	    if (match && !(flags & match))  continue;	/*  XXX: optimize it */	    for (a = arg, o = optn->long_opt; *o && *a == *o; a++, o++) ;	    if (*a == '\0' ||		(*a == '=' && optn->arg_name && !(flags & _CLIF_STRICT_NOEQUAL))	    ) {	    /*  looks like end of option...  */		if (!*o) {	/*  explicit match found   */		    if (*a == '=' && arg_p)  *arg_p = a + 1;		    return optn;		}		if ((flags & CLIF_ABBREV) &&		    (a - arg >= CLIF_MIN_ABBREV)		) {		    if (!abbrev_found) {			abbrev_found = 1;			abbrev = optn;			if (*a == '=')  abbrev_arg = a + 1;		    } else	/*  several possibility case...  */			abbrev = NULL;		}	    }	}	if (abbrev) {	/*  implicit match found   */	    if (abbrev_arg && arg_p)  *arg_p = abbrev_arg;	    return abbrev;	} else		/*  no match found   */	    return NULL;}static int check_sym (const CLIF_option *optn, char sym) {	if (sym == '+') {	    if (!optn->function_plus)  return -1;	}	else if (sym == '-') {	    if (!optn->function && optn->function_plus)		    return -1;	}	return 0;}static int call_function (CLIF_option *optn, char *opt_arg, char sym) {	int (*function) (CLIF_option *, char *);	function = (sym == '+') ? optn->function_plus : optn->function;	if (!function)  return 0;	if (opt_arg && ((optn->flags | curr.parse_flags) & CLIF_SEVERAL)) {	    char tmp[80];	    char *t;	    char *endt = tmp + sizeof (tmp);	    while (*opt_arg) {    		t = tmp;		while (t < endt && *opt_arg &&		       *opt_arg != ' ' && *opt_arg != '\t' && *opt_arg != ','		)  *t++ = *opt_arg++;		if (t >= endt)  return -1;    		*t = '\0';    		if (function (optn, tmp) < 0)  return -1;    		while (*opt_arg == ' ' || *opt_arg == '\t' || *opt_arg == ',')			opt_arg++;	    }	    return 0;	}	return  function (optn, opt_arg);}int CLIF_parse_cmdline (int argc, char *argv[],			CLIF_option *option_list,			CLIF_argument *argument_list,			unsigned int parse_flags) {	int i, j;	CLIF_option *optn;	CLIF_argument *argm;	int num_args = 0;	int num_argm = 0, strict_beg = 0, strict_end = 0;	_CLIF_index arg_n[MAX_ARGC_NUMBER];	unsigned int dirty_flags = 0;	int dirty_plus = 0;	int exclusive_cnt = 0;	int posix = getenv ("POSIXLY_CORRECT") != NULL ||					    (parse_flags & CLIF_POSIX);	curr.argc = argc;	curr.argv = argv;	curr.option_list = option_list;	curr.argument_list = argument_list;	curr.parse_flags = parse_flags;	if (argc <= 1 && (parse_flags & CLIF_HELP_EMPTY)) {		CLIF_current_help ();		exit (0);	}	/*  Scan argument_list for check and some info.  */	if (argument_list) {	    enum stages { STRICT_BEG, OPTIONAL, STRICT_END };	    int stage = STRICT_BEG;	    for (argm = argument_list; argm->name; argm++) {				if (argm->flags & CLIF_STRICT) {		    if (stage == STRICT_BEG)  strict_beg++;		    else if (stage == OPTIONAL) {			stage = STRICT_END;			strict_end++;		    }		    else if (stage == STRICT_END)			    strict_end++;		} else {		    if (stage == STRICT_BEG)  stage = OPTIONAL;		    else if (stage == STRICT_END) {			err_report ("Incorrect argument list set in program "				    "source: more than one optional area.");			return -1;		    }		}		num_argm++;	    }	}	/*  Scan option_list for some info.  */	if (option_list) {	    dirty_flags = parse_flags;	    for (optn = option_list;		    optn->short_opt || optn->long_opt;			optn++	    ) {		dirty_flags |= optn->flags;		if (optn->function_plus)  dirty_plus = 1;	    }	}	if (dirty_flags & CLIF_EXCL)		exclusive_cnt = 1;	/*  only one is allowed...  */	/*  Go !   Store arguments, parse options.  */	for (i = 1; i < argc; i++) {	    char *arg = argv[i];	    char *opt_arg = NULL;	    char sym = '-';	    if (!option_list)		    goto  handle_arg;	    if (*arg == '+' && dirty_plus)		    sym = '+';	    if (*arg != sym) {	/*  argument or keyword   */		if (dirty_flags & CLIF_MAY_KEYWORD) {		    optn = find_long (arg, &opt_arg, CLIF_MAY_KEYWORD, 0);		    if (optn)  goto long_found;		}		if (num_args == 0 && (parse_flags & CLIF_FIRST_GROUP)) {		    /*  ugly...  */		    parse_flags &= ~CLIF_FIRST_GROUP;		    dirty_flags &= ~CLIF_FIRST_GROUP;	/*  to be correct   */		    goto  handle_short;		}		/*  else it is an argument   */		goto  handle_arg;	    }	    else if (*++arg == sym) {	/*  `--' - long option   */		arg++;		if (*arg == sym ||	/*  `---' - let it be not option... */		    (parse_flags & (_CLIF_STRICT_KEYWORD|_CLIF_STRICT_ONEDASH)) 		) {		    arg -= 2;		    goto  handle_arg;	/*  not option anyway  */		}			optn = find_long (arg, &opt_arg, 0,				_CLIF_STRICT_KEYWORD | _CLIF_STRICT_ONEDASH);		if (optn)  goto long_found;			/*  XXX: May be allow only for `--', not `++' too...  */		if (!*arg && sym == '-') {  /*  `--' and no empty longoption */		    option_list = NULL;	    /*  POSIX way...  */		    continue;		}			/*  XXX: or treat as an argument sometimes???  */		err_bad_opt (argv[i], 0, i);		return -1;	    }	    else {	/*  short option, or several short options...  */		if (dirty_flags & CLIF_MAY_ONEDASH) {		    optn = find_long (arg, &opt_arg, CLIF_MAY_ONEDASH, 0);		    if (optn)  goto long_found;		}    		if (!*arg) {	/*  POSIX say: only "stdout specification"... */		    arg--;		    goto handle_arg;		}    		goto  handle_short;	    }    long_found:		    if (check_sym (optn, sym) < 0) {	/*  Oops...  */		err_bad_opt (argv[i], 0, i);		return -1;	    }	    if (optn->flags & CLIF_EXCL) {		if (!exclusive_cnt) {		    err_bad_excl (optn, 0, i);		    return -1;		}		exclusive_cnt--;	    }			    if (optn->arg_name && !opt_arg) {		unsigned int flags = optn->flags | parse_flags;		if (++i >= argc ||		    !(flags & CLIF_MAY_NOEQUAL)		) {	/*  missing opt arg   */		    i--;		    if (!(flags & CLIF_OPTARG)) {			err_bad_arg (optn, 0, i);			return -1;		    }		    opt_arg = NULL;		} else		    opt_arg = argv[i];		   	    }	    if (call_function (optn, opt_arg, sym) < 0) {		err_bad_res (optn, 0, opt_arg, i);		return -1;	    }	    if (optn->flags & CLIF_EXIT)		    exit (0);	    continue;    handle_arg:	    if (argument_list) {		if (i < MAX_ARGC_NUMBER)    /*  XXX: ugly, better report   */			arg_n[num_args++] = i;	    } else {		err_report ("`%s' (argc %d): arguments are not allowed",								 argv[i], i);		return -1;	    }	    /*  POSIX say: No more options after args...  */	    if (posix)  option_list = NULL;	/*  geniously...  */		    continue;    handle_short:	    opt_arg = NULL;	    do {		for (optn = option_list;			optn->short_opt || optn->long_opt;			    optn++		) {		    if (optn->short_opt && optn->short_opt[0] == *arg)			    break;		}		if (!optn->short_opt ||		    check_sym (optn, sym) < 0		) {		    err_bad_opt (argv[i], *arg, i);		    return -1;		}		if (optn->flags & CLIF_EXCL) {		    if (!exclusive_cnt) {			err_bad_excl (optn, *arg, i);			return -1;		    }		    exclusive_cnt--;		}		if (optn->arg_name) {		    unsigned int flags = parse_flags | optn->flags;		    if (arg[1] == '\0') {	/*  a last one   */			/*  POSIX say: an option with arg cannot be grouped. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -