source: branches/1.5x/libtransmission/tr-getopt.c @ 8204

Last change on this file since 8204 was 8204, checked in by charles, 13 years ago

(1.5x libT) various backports for 1.52:
(1) recognize Aria2 as a client
(2) remove jhujhiti's tr_suspectAddress(), since he removed it from trunka
(3) on Mac, better detection of where the Web UI files are located
(4) reintroduce the web task queue
(5) various minor formatting changes to reduce the diffs between 1.52 and trunk

File size: 5.8 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.com>
3 *
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.
9 *
10 * $Id: tr-getopt.c 7783 2009-01-23 18:44:15Z charles $
11 */
12
13#include <stdio.h>
14#include <stdlib.h> /* exit() */
15#include <string.h>
16
17#include "tr-getopt.h"
18
19#ifndef MAX
20 #define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
21#endif
22
23int tr_optind = 1;
24
25static const char*
26getArgName( const tr_option * opt )
27{
28    const char * arg;
29
30    if( !opt->has_arg )
31        arg = "";
32    else if( opt->argName )
33        arg = opt->argName;
34    else
35        arg = "<args>";
36
37    return arg;
38}
39
40static void
41getopts_usage_line( const tr_option * opt,
42                    int               longWidth,
43                    int               shortWidth,
44                    int               argWidth )
45{
46    const char * longName   = opt->longName ? opt->longName : "";
47    const char * shortName  = opt->shortName ? opt->shortName : "";
48    const char * arg        = getArgName( opt );
49
50    printf( "  %s%-*s %s%-*s %-*s  %s\n",
51            (shortName && *shortName ? "-" : " "), shortWidth, shortName,
52            (longName && *longName ? "--" : "  "), longWidth, longName,
53            argWidth, arg,
54            opt->description );
55}
56
57static void
58maxWidth( const struct tr_option * o,
59          int *                    longWidth,
60          int *                    shortWidth,
61          int *                    argWidth )
62{
63    const char * arg;
64
65    if( o->longName )
66        *longWidth = MAX( *longWidth, (int)strlen( o->longName ) );
67
68    if( o->shortName )
69        *shortWidth = MAX( *shortWidth, (int)strlen( o->shortName ) );
70
71    if( ( arg = getArgName( o ) ) )
72        *argWidth = MAX( *argWidth, (int)strlen( arg ) );
73}
74
75void
76tr_getopt_usage( const char *           progName,
77                 const char *           description,
78                 const struct tr_option opts[] )
79{
80    int                      longWidth = 0;
81    int                      shortWidth = 0;
82    int                      argWidth = 0;
83    struct tr_option         help;
84    const struct tr_option * o;
85
86    for( o = opts; o->val; ++o )
87        maxWidth( o, &longWidth, &shortWidth, &argWidth );
88
89    help.val = -1;
90    help.longName = "help";
91    help.description = "Display this help page and exit";
92    help.shortName = "h";
93    help.has_arg = 0;
94    maxWidth( &help, &longWidth, &shortWidth, &argWidth );
95
96    if( description == NULL )
97        description = "Usage: %s [options]";
98    printf( description, progName );
99    printf( "\n\nOptions:\n" );
100    getopts_usage_line( &help, longWidth, shortWidth, argWidth );
101    for( o = opts; o->val; ++o )
102        getopts_usage_line( o, longWidth, shortWidth, argWidth );
103}
104
105static const tr_option *
106findOption( const tr_option * opts,
107            const char *      str,
108            const char **     setme_arg )
109{
110    size_t            matchlen = 0;
111    const char *      arg = NULL;
112    const tr_option * o;
113    const tr_option * match = NULL;
114
115    /* find the longest matching option */
116    for( o = opts; o->val; ++o )
117    {
118        size_t len = o->longName ? strlen( o->longName ) : 0;
119
120        if( ( matchlen < len ) && !memcmp( str, "--", 2 )
121          && !memcmp( str + 2, o->longName, len )
122          && ( str[len + 2] == '\0' || ( o->has_arg && str[len + 2] == '=' ) ) )
123        {
124            matchlen = len;
125            match = o;
126            arg = str[len + 2] == '=' ? str + len + 3 : NULL;
127        }
128
129        len = o->shortName ? strlen( o->shortName ) : 0;
130
131        if( ( matchlen < len ) && !memcmp( str, "-", 1 )
132          && !memcmp( str + 1, o->shortName, len )
133          && ( str[len + 1] == '\0' || o->has_arg ) )
134        {
135            matchlen = len;
136            match = o;
137            switch( str[len + 1] )
138            {
139                case '\0':
140                    arg = NULL;          break;
141
142                case '=':
143                    arg = str + len + 2; break;
144
145                default:
146                    arg = str + len + 1; break;
147            }
148        }
149    }
150
151    if( setme_arg )
152        *setme_arg = arg;
153
154    return match;
155}
156
157int
158tr_getopt( const char *      usage,
159           int               argc,
160           const char **     argv,
161           const tr_option * opts,
162           const char **     setme_optarg )
163{
164    int               i;
165    const char *      arg = NULL;
166    const tr_option * o = NULL;
167
168    *setme_optarg = NULL;
169
170    /* handle the builtin 'help' option */
171    for( i = 1; i < argc; ++i )
172    {
173        if( !strcmp( argv[i], "-h" ) || !strcmp( argv[i], "--help" ) )
174        {
175            tr_getopt_usage( argv[0], usage, opts );
176            exit( 0 );
177        }
178    }
179
180    /* out of options? */
181    if( argc == 1 || tr_optind >= argc )
182        return TR_OPT_DONE;
183
184    o = findOption( opts, argv[tr_optind], &arg );
185    if( !o )
186    {
187        /* let the user know we got an unknown option... */
188        *setme_optarg = argv[tr_optind++];
189        return TR_OPT_UNK;
190    }
191
192    if( !o->has_arg )
193    {
194        /* no argument needed for this option, so we're done */
195        if( arg )
196            return TR_OPT_ERR;
197        *setme_optarg = NULL;
198        ++tr_optind;
199        return o->val;
200    }
201
202    /* option needed an argument, and it was embedded in this string */
203    if( arg )
204    {
205        *setme_optarg = arg;
206        ++tr_optind;
207        return o->val;
208    }
209
210    /* throw an error if the option needed an argument but didn't get one */
211    if( ++tr_optind >= argc )
212        return TR_OPT_ERR;
213    if( findOption( opts, argv[tr_optind], NULL ) )
214        return TR_OPT_ERR;
215
216    *setme_optarg = argv[tr_optind++];
217    return o->val;
218}
Note: See TracBrowser for help on using the repository browser.