aboutsummaryrefslogblamecommitdiffstats
path: root/libsimple-arg.h
blob: d63a7ec554e189d95e1d680240a237d247b78c98 (plain) (tree)



































































































































































                                                                                                                           
/* See LICENSE file for copyright and license details. */
#ifndef LIBSIMPLE_ARG_H
#define LIBSIMPLE_ARG_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



extern char *argv0;


struct longopt {
	const char *long_flag;
	char short_flag;
	int with_arg;
};


#define ARGBEGIN    ARGBEGIN3(1, argc, argv)
#define SUBARGBEGIN ARGBEGIN3(0, argc, argv)

#define ARGBEGIN3(WITH_ARGV0, argc, argv)\
	do {\
		char flag_, *lflag_, *arg_;\
		int brk_ = 0, again_;\
		size_t i_, n_;\
		if (WITH_ARGV0) {\
			argv0 = *argv;\
			argv += !!argv0;\
			argc -= !!argv0;\
		}\
		for (; argv[0] && argv[0][0] && argv[0][1]; argc--, argv++) {\
			lflag_ = argv[0];\
			if (argv[0][0] == '-') {\
				if (argv[0][1] == '-' && !argv[0][2]) {\
					argv++, argc--;\
					break;\
				}\
				for (argv[0]++; argv[0][0]; argv[0]++) {\
					flag_ = argv[0][0];\
					if (flag_ == '-' && &argv[0][-1] != lflag_)\
						usage();\
					arg_ = argv[0][1] ? &argv[0][1] : argv[1];\
					do {\
						again_ = 0;\
						switch (flag_) {

#define ARGMAPLONG(LONGOPTS)\
						for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\
							if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\
								flag_ = (LONGOPTS)[i_].short_flag;\
								again_ = 1;\
								break;\
							}\
						}\
						if (again_)\
							break

#define ARGALT(SYMBOL)\
						}\
					} while (again_);\
					if (brk_) {\
						argc -= arg_ == argv[1];\
						argv += arg_ == argv[1];\
						brk_ = 0;\
						break;\
					}\
				}\
			} else if (argv[0][0] == SYMBOL) {\
				if (argv[0][1] == SYMBOL && !argv[0][2])\
					break;\
				for (argv[0]++; argv[0][0]; argv[0]++) {\
					flag_ = argv[0][0];\
					if (flag_ == SYMBOL && &argv[0][-1] != lflag_)\
						usage();\
					arg_ = argv[0][1] ? &argv[0][1] : argv[1];\
					do {\
						again_ = 0;\
						switch (flag_) {

#define ARGEND\
						}\
					} while (again_);\
					if (brk_) {\
						argc -= arg_ == argv[1];\
						argv += arg_ == argv[1];\
						brk_ = 0;\
						break;\
					}\
				}\
			} else {\
				break;\
			}\
		}\
	} while (0)


#define ARGNUM         '0': case '1': case '2': case '3': case '4':\
                  case '5': case '6': case '7': case '8': case '9'

#define FLAG()    (flag_)
#define LFLAG()   (lflag_)
#define ARG()     (arg_ ? (brk_ = 1, arg_) : (usage(), (char *)0))
#define ARGHERE() (brk_ = 1, argv[0])


#define NOFLAGS(...)\
	do {\
		if (*argv)\
			argv0 = *argv++, argc--;\
		if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && !argv[0][2])\
			argv++, argc--;\
		else if (argv[0] && argv[0][0] == '-')\
			usage();\
		if (__VA_ARGS__)\
			usage();\
	} while (0)


#define TESTLONG(FLG, WARG)\
	((WARG)\
	 ? ((!strncmp(lflag_, (FLG), n_ = strlen(FLG)) && lflag_[n_] == '=')\
	    ? (lflag_[n_] = '\0',\
	       (arg_ = &lflag_[n_ + 1]),\
	       (brk_ = 1))\
	    : (!strcmp(lflag_, (FLG))\
	       ? (argv[1]\
	          ? ((arg_ = argv[1]),\
	             (brk_ = 1))\
	          : (usage(), 0))\
	       : 0))\
	 : (!strcmp(lflag_, (FLG))\
	    ? (brk_ = 1)\
	    : 0))


#define USAGE(SYNOPSIS)\
	NUSAGE(1, SYNOPSIS)

#if defined(__GNUC__) || defined(__clang__)
# define NUSAGE(STATUS, SYNOPSIS)\
	__attribute__((noreturn))\
	static void usage(void)\
	{\
		const char *syn = SYNOPSIS ? SYNOPSIS : "";\
		fprintf(stderr, "usage: %s%s%s\n", argv0, *syn ? " " : "", syn);\
		exit(STATUS);\
	}\
	char *argv0
#else
# define NUSAGE(STATUS, SYNOPSIS)\
	static void usage(void)\
	{\
		const char *syn = SYNOPSIS ? SYNOPSIS : "";\
		fprintf(stderr, "usage: %s%s%s\n", argv0, *syn ? " " : "", syn);\
		exit(STATUS);\
	}\
	char *argv0
#endif


#endif