transmission 2.83
[tomato.git] / release / src / router / transmission / libtransmission / tr-getopt.c
blob129b6260952124baeb88c0d11cd02cea8e8365e2
1 /*
2 * This file Copyright (C) 2008-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: tr-getopt.c 14241 2014-01-21 03:10:30Z jordan $
8 */
10 #include <ctype.h> /* isspace () */
11 #include <stdio.h>
12 #include <stdlib.h> /* exit () */
13 #include <string.h>
15 #include "tr-getopt.h"
17 #ifndef MAX
18 #define MAX(a, b)(((a) > (b)) ? (a) : (b))
19 #endif
21 int tr_optind = 1;
23 static const char*
24 getArgName (const tr_option * opt)
26 const char * arg;
28 if (!opt->has_arg)
29 arg = "";
30 else if (opt->argName)
31 arg = opt->argName;
32 else
33 arg = "<args>";
35 return arg;
38 static int
39 get_next_line_len (const char * description, int maxlen)
41 int end;
42 int len = strlen (description);
44 if (len < maxlen)
45 return len;
47 end = maxlen < len ? maxlen : len;
48 while ((end > 0) && !isspace (description[end]))
49 --end;
51 return end ? end : len;
54 static void
55 getopts_usage_line (const tr_option * opt,
56 int longWidth,
57 int shortWidth,
58 int argWidth)
60 int len;
61 const char * longName = opt->longName ? opt->longName : "";
62 const char * shortName = opt->shortName ? opt->shortName : "";
63 const char * arg = getArgName (opt);
65 const int d_indent = shortWidth + longWidth + argWidth + 7;
66 const int d_width = 80 - d_indent;
67 const char * d = opt->description;
69 printf (" %s%-*s %s%-*s %-*s ",
70 (shortName && *shortName ? "-" : " "), shortWidth, shortName,
71 (longName && *longName ? "--" : " "), longWidth, longName,
72 argWidth, arg);
73 len = get_next_line_len (d, d_width);
74 printf ("%*.*s\n", len, len, d);
76 d += len;
77 while (isspace (*d)) ++d;
79 while ((len = get_next_line_len (d, d_width))) {
80 printf ("%*.*s%*.*s\n", d_indent, d_indent, "", len, len, d);
81 d += len;
82 while (isspace (*d)) ++d;
86 static void
87 maxWidth (const struct tr_option * o,
88 int * longWidth,
89 int * shortWidth,
90 int * argWidth)
92 const char * arg;
94 if (o->longName)
95 *longWidth = MAX (*longWidth, (int)strlen (o->longName));
97 if (o->shortName)
98 *shortWidth = MAX (*shortWidth, (int)strlen (o->shortName));
100 if ((arg = getArgName (o)))
101 *argWidth = MAX (*argWidth, (int)strlen (arg));
104 void
105 tr_getopt_usage (const char * progName,
106 const char * description,
107 const struct tr_option opts[])
109 int longWidth = 0;
110 int shortWidth = 0;
111 int argWidth = 0;
112 struct tr_option help;
113 const struct tr_option * o;
115 for (o = opts; o->val; ++o)
116 maxWidth (o, &longWidth, &shortWidth, &argWidth);
118 help.val = -1;
119 help.longName = "help";
120 help.description = "Display this help page and exit";
121 help.shortName = "h";
122 help.has_arg = 0;
123 maxWidth (&help, &longWidth, &shortWidth, &argWidth);
125 if (description == NULL)
126 description = "Usage: %s [options]";
127 printf (description, progName);
128 printf ("\n\nOptions:\n");
129 getopts_usage_line (&help, longWidth, shortWidth, argWidth);
130 for (o = opts; o->val; ++o)
131 getopts_usage_line (o, longWidth, shortWidth, argWidth);
134 static const tr_option *
135 findOption (const tr_option * opts,
136 const char * str,
137 const char ** setme_arg)
139 size_t matchlen = 0;
140 const char * arg = NULL;
141 const tr_option * o;
142 const tr_option * match = NULL;
144 /* find the longest matching option */
145 for (o = opts; o->val; ++o)
147 size_t len = o->longName ? strlen (o->longName) : 0;
149 if ((matchlen < len)
150 && (str[0] == '-')
151 && (str[1] == '-')
152 && !strncmp (str+2, o->longName, len)
153 && (str[len + 2] == '\0' || (o->has_arg && str[len + 2] == '=')))
155 matchlen = len;
156 match = o;
157 arg = str[len + 2] == '=' ? str + len + 3 : NULL;
160 len = o->shortName ? strlen (o->shortName) : 0;
162 if ((matchlen < len)
163 && (str[0] == '-')
164 && !strncmp (str+1, o->shortName, len)
165 && (str[len + 1] == '\0' || o->has_arg))
167 matchlen = len;
168 match = o;
169 switch (str[len + 1])
171 case '\0':
172 arg = NULL; break;
174 case '=':
175 arg = str + len + 2; break;
177 default:
178 arg = str + len + 1; break;
183 if (setme_arg)
184 *setme_arg = arg;
186 return match;
190 tr_getopt (const char * usage,
191 int argc,
192 const char ** argv,
193 const tr_option * opts,
194 const char ** setme_optarg)
196 int i;
197 const char * arg = NULL;
198 const tr_option * o = NULL;
200 *setme_optarg = NULL;
202 /* handle the builtin 'help' option */
203 for (i = 1; i < argc; ++i)
205 if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help"))
207 tr_getopt_usage (argv[0], usage, opts);
208 exit (0);
212 /* out of options? */
213 if (argc == 1 || tr_optind >= argc)
214 return TR_OPT_DONE;
216 o = findOption (opts, argv[tr_optind], &arg);
217 if (!o)
219 /* let the user know we got an unknown option... */
220 *setme_optarg = argv[tr_optind++];
221 return TR_OPT_UNK;
224 if (!o->has_arg)
226 /* no argument needed for this option, so we're done */
227 if (arg)
228 return TR_OPT_ERR;
229 *setme_optarg = NULL;
230 ++tr_optind;
231 return o->val;
234 /* option needed an argument, and it was embedded in this string */
235 if (arg)
237 *setme_optarg = arg;
238 ++tr_optind;
239 return o->val;
242 /* throw an error if the option needed an argument but didn't get one */
243 if (++tr_optind >= argc)
244 return TR_OPT_ERR;
245 if (findOption (opts, argv[tr_optind], NULL))
246 return TR_OPT_ERR;
248 *setme_optarg = argv[tr_optind++];
249 return o->val;