Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / libtransmission / tr-getopt.c
blob7dac096768bf098879ee58c3b9e91e24c786ad2b
1 /*
2 * This file Copyright (C) 2008-2010 Mnemosyne LLC
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
10 * $Id: tr-getopt.c 10782 2010-06-16 14:05:18Z charles $
13 #include <ctype.h> /* isspace() */
14 #include <stdio.h>
15 #include <stdlib.h> /* exit() */
16 #include <string.h>
18 #include "tr-getopt.h"
20 #ifndef MAX
21 #define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
22 #endif
24 int tr_optind = 1;
26 static const char*
27 getArgName( const tr_option * opt )
29 const char * arg;
31 if( !opt->has_arg )
32 arg = "";
33 else if( opt->argName )
34 arg = opt->argName;
35 else
36 arg = "<args>";
38 return arg;
41 static int
42 get_next_line_len( const char * description, int maxlen )
44 int end;
45 int len = strlen( description );
47 if( len < maxlen )
48 return len;
50 end = maxlen < len ? maxlen : len;
51 while( ( end > 0 ) && !isspace( description[end] ) )
52 --end;
54 return end ? end : len;
57 static void
58 getopts_usage_line( const tr_option * opt,
59 int longWidth,
60 int shortWidth,
61 int argWidth )
63 int len;
64 const char * longName = opt->longName ? opt->longName : "";
65 const char * shortName = opt->shortName ? opt->shortName : "";
66 const char * arg = getArgName( opt );
68 const int d_indent = shortWidth + longWidth + argWidth + 7;
69 const int d_width = 80 - d_indent;
70 const char * d = opt->description;
72 printf( " %s%-*s %s%-*s %-*s ",
73 (shortName && *shortName ? "-" : " "), shortWidth, shortName,
74 (longName && *longName ? "--" : " "), longWidth, longName,
75 argWidth, arg );
76 len = get_next_line_len( d, d_width );
77 printf( "%*.*s\n", len, len, d );
79 d += len;
80 while( isspace( *d ) ) ++d;
82 while(( len = get_next_line_len( d, d_width ))) {
83 printf( "%*.*s%*.*s\n", d_indent, d_indent, "", len, len, d );
84 d += len;
85 while( isspace( *d ) ) ++d;
89 static void
90 maxWidth( const struct tr_option * o,
91 int * longWidth,
92 int * shortWidth,
93 int * argWidth )
95 const char * arg;
97 if( o->longName )
98 *longWidth = MAX( *longWidth, (int)strlen( o->longName ) );
100 if( o->shortName )
101 *shortWidth = MAX( *shortWidth, (int)strlen( o->shortName ) );
103 if( ( arg = getArgName( o ) ) )
104 *argWidth = MAX( *argWidth, (int)strlen( arg ) );
107 void
108 tr_getopt_usage( const char * progName,
109 const char * description,
110 const struct tr_option opts[] )
112 int longWidth = 0;
113 int shortWidth = 0;
114 int argWidth = 0;
115 struct tr_option help;
116 const struct tr_option * o;
118 for( o = opts; o->val; ++o )
119 maxWidth( o, &longWidth, &shortWidth, &argWidth );
121 help.val = -1;
122 help.longName = "help";
123 help.description = "Display this help page and exit";
124 help.shortName = "h";
125 help.has_arg = 0;
126 maxWidth( &help, &longWidth, &shortWidth, &argWidth );
128 if( description == NULL )
129 description = "Usage: %s [options]";
130 printf( description, progName );
131 printf( "\n\nOptions:\n" );
132 getopts_usage_line( &help, longWidth, shortWidth, argWidth );
133 for( o = opts; o->val; ++o )
134 getopts_usage_line( o, longWidth, shortWidth, argWidth );
137 static const tr_option *
138 findOption( const tr_option * opts,
139 const char * str,
140 const char ** setme_arg )
142 size_t matchlen = 0;
143 const char * arg = NULL;
144 const tr_option * o;
145 const tr_option * match = NULL;
147 /* find the longest matching option */
148 for( o = opts; o->val; ++o )
150 size_t len = o->longName ? strlen( o->longName ) : 0;
152 if( ( matchlen < len ) && !memcmp( str, "--", 2 )
153 && !memcmp( str + 2, o->longName, len )
154 && ( str[len + 2] == '\0' || ( o->has_arg && str[len + 2] == '=' ) ) )
156 matchlen = len;
157 match = o;
158 arg = str[len + 2] == '=' ? str + len + 3 : NULL;
161 len = o->shortName ? strlen( o->shortName ) : 0;
163 if( ( matchlen < len ) && !memcmp( str, "-", 1 )
164 && !memcmp( 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;